Add Tracking Protection Info Panel
parent
9e83edcac5
commit
4485b7f647
|
@ -425,6 +425,8 @@ dependencies {
|
|||
|
||||
implementation Deps.autodispose
|
||||
|
||||
implementation Deps.lottie
|
||||
|
||||
implementation Deps.adjust
|
||||
implementation Deps.installreferrer // Required by Adjust
|
||||
|
||||
|
|
|
@ -21,5 +21,6 @@ enum class BrowserDirection(@IdRes val fragmentId: Int) {
|
|||
FromBookmarks(R.id.bookmarkFragment),
|
||||
FromHistory(R.id.historyFragment),
|
||||
FromExceptions(R.id.exceptionsFragment),
|
||||
FromAbout(R.id.aboutFragment)
|
||||
FromAbout(R.id.aboutFragment),
|
||||
FromTrackingProtection(R.id.trackingProtectionFragment)
|
||||
}
|
||||
|
|
|
@ -37,6 +37,11 @@ object FeatureFlags {
|
|||
*/
|
||||
const val mediaIntegration = true
|
||||
|
||||
/**
|
||||
* Displays the categories blocked by ETP in a panel in the toolbar
|
||||
*/
|
||||
val etpCategories = nightly or debug
|
||||
|
||||
/**
|
||||
* Granular data deletion provides additional choices on the Delete Browsing Data
|
||||
* setting screen for cookies, cached images and files, and site permissions.
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.mozilla.fenix.library.history.HistoryFragmentDirections
|
|||
import org.mozilla.fenix.search.SearchFragmentDirections
|
||||
import org.mozilla.fenix.settings.AboutFragmentDirections
|
||||
import org.mozilla.fenix.settings.SettingsFragmentDirections
|
||||
import org.mozilla.fenix.settings.TrackingProtectionFragmentDirections
|
||||
import org.mozilla.fenix.share.ShareFragment
|
||||
import org.mozilla.fenix.theme.DefaultThemeManager
|
||||
import org.mozilla.fenix.theme.ThemeManager
|
||||
|
@ -236,6 +237,10 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
|||
)
|
||||
BrowserDirection.FromAbout ->
|
||||
AboutFragmentDirections.actionAboutFragmentToBrowserFragment(customTabSessionId)
|
||||
BrowserDirection.FromTrackingProtection ->
|
||||
TrackingProtectionFragmentDirections.actionTrackingProtectionFragmentToBrowserFragment(
|
||||
customTabSessionId
|
||||
)
|
||||
}
|
||||
|
||||
private fun load(
|
||||
|
|
|
@ -207,6 +207,10 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||
showQuickSettingsDialog()
|
||||
}
|
||||
|
||||
browserToolbarView.view.setOnTrackingProtectionClickedListener {
|
||||
showTrackingProtectionPanel()
|
||||
}
|
||||
|
||||
contextMenuFeature.set(
|
||||
feature = ContextMenuFeature(
|
||||
requireFragmentManager(),
|
||||
|
@ -487,6 +491,8 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||
|
||||
protected abstract fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?)
|
||||
|
||||
protected abstract fun navToTrackingProtectionPanel(session: Session)
|
||||
|
||||
/**
|
||||
* Returns the top and bottom margins.
|
||||
*/
|
||||
|
@ -530,6 +536,13 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||
}
|
||||
}
|
||||
|
||||
private fun showTrackingProtectionPanel() {
|
||||
val session = getSessionById() ?: return
|
||||
view?.let {
|
||||
navToTrackingProtectionPanel(session)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current session.
|
||||
*/
|
||||
|
|
|
@ -4,12 +4,17 @@
|
|||
|
||||
package org.mozilla.fenix.browser
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.RadioButton
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Observer
|
||||
|
@ -18,6 +23,7 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.transition.TransitionInflater
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
||||
import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.*
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
@ -31,6 +37,8 @@ import mozilla.components.feature.sitepermissions.SitePermissions
|
|||
import mozilla.components.lib.state.ext.consumeFrom
|
||||
import mozilla.components.support.base.feature.BackHandler
|
||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||
import mozilla.components.support.ktx.android.util.dpToPx
|
||||
import org.mozilla.fenix.FeatureFlags
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
|
||||
|
@ -42,8 +50,10 @@ import org.mozilla.fenix.components.toolbar.BrowserToolbarController
|
|||
import org.mozilla.fenix.components.toolbar.BrowserToolbarViewInteractor
|
||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetAction
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
import org.mozilla.fenix.ext.nav
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlChange
|
||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||
|
@ -139,6 +149,18 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
).also { observer ->
|
||||
getSessionById()?.register(observer, this, autoPause = true)
|
||||
}
|
||||
getSessionById()?.register(toolbarSessionObserver, this, autoPause = true)
|
||||
}
|
||||
|
||||
private val toolbarSessionObserver = object : Session.Observer {
|
||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
||||
if (!loading &&
|
||||
context!!.settings.shouldShowTrackingProtectionOnboarding &&
|
||||
session.trackerBlockingEnabled
|
||||
) {
|
||||
showTrackingProtectionOnboarding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -181,14 +203,26 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
}
|
||||
|
||||
override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) {
|
||||
val directions = BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment(
|
||||
sessionId = session.id,
|
||||
url = session.url,
|
||||
isSecured = session.securityInfo.secure,
|
||||
isTrackingProtectionOn = session.trackerBlockingEnabled,
|
||||
sitePermissions = sitePermissions,
|
||||
gravity = getAppropriateLayoutGravity()
|
||||
)
|
||||
val directions =
|
||||
BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment(
|
||||
sessionId = session.id,
|
||||
url = session.url,
|
||||
isSecured = session.securityInfo.secure,
|
||||
isTrackingProtectionOn = session.trackerBlockingEnabled,
|
||||
sitePermissions = sitePermissions,
|
||||
gravity = getAppropriateLayoutGravity()
|
||||
)
|
||||
nav(R.id.browserFragment, directions)
|
||||
}
|
||||
|
||||
override fun navToTrackingProtectionPanel(session: Session) {
|
||||
val directions =
|
||||
BrowserFragmentDirections.actionBrowserFragmentToTrackingProtectionPanelDialogFragment(
|
||||
sessionId = session.id,
|
||||
url = session.url,
|
||||
trackingProtectionEnabled = session.trackerBlockingEnabled,
|
||||
gravity = getAppropriateLayoutGravity()
|
||||
)
|
||||
nav(R.id.browserFragment, directions)
|
||||
}
|
||||
|
||||
|
@ -309,8 +343,44 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private fun showTrackingProtectionOnboarding() {
|
||||
if (!FeatureFlags.etpCategories) {
|
||||
return
|
||||
}
|
||||
context?.let {
|
||||
it.settings.incrementTrackingProtectionOnboardingCount()
|
||||
val layout = LayoutInflater.from(it)
|
||||
.inflate(R.layout.tracking_protection_onboarding_popup, null)
|
||||
layout.onboarding_message.text =
|
||||
it.getString(R.string.etp_onboarding_message, getString(R.string.app_name))
|
||||
val trackingOnboarding =
|
||||
PopupWindow(
|
||||
layout,
|
||||
TP_ONBOARDING_WIDTH.dpToPx(resources.displayMetrics),
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
true
|
||||
)
|
||||
val closeButton = layout.findViewById<ImageView>(R.id.close_onboarding)
|
||||
closeButton.increaseTapArea(BUTTON_INCREASE_DPS)
|
||||
closeButton.setOnClickListener {
|
||||
trackingOnboarding.dismiss()
|
||||
}
|
||||
trackingOnboarding.isOutsideTouchable = true
|
||||
trackingOnboarding.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
trackingOnboarding.showAtLocation(
|
||||
browserToolbarView.view,
|
||||
Gravity.BOTTOM or Gravity.START,
|
||||
TP_ONBOARDING_X_OFFSET.dpToPx(resources.displayMetrics),
|
||||
browserToolbarView.view.height
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val BUTTON_INCREASE_DPS = 12
|
||||
private const val TP_ONBOARDING_X_OFFSET = 4
|
||||
private const val SHARED_TRANSITION_MS = 200L
|
||||
private const val TP_ONBOARDING_WIDTH = 256
|
||||
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
||||
const val REPORT_SITE_ISSUE_URL =
|
||||
"https://webcompat.com/issues/new?url=%s&label=browser-fenix"
|
||||
|
|
|
@ -98,7 +98,10 @@ class Core(private val context: Context) {
|
|||
withContext(Dispatchers.IO) {
|
||||
sessionStorage.restore()
|
||||
}?.let { snapshot ->
|
||||
sessionManager.restore(snapshot, updateSelection = (sessionManager.selectedSession == null))
|
||||
sessionManager.restore(
|
||||
snapshot,
|
||||
updateSelection = (sessionManager.selectedSession == null)
|
||||
)
|
||||
}
|
||||
|
||||
// Now that we have restored our previous state (if there's one) let's setup auto saving the state while
|
||||
|
@ -151,7 +154,9 @@ class Core(private val context: Context) {
|
|||
normalMode: Boolean = context.settings.shouldUseTrackingProtection,
|
||||
privateMode: Boolean = true
|
||||
): TrackingProtectionPolicy {
|
||||
val trackingProtectionPolicy = TrackingProtectionPolicy.recommended()
|
||||
val trackingProtectionPolicy =
|
||||
if (context.settings.useStrictTrackingProtection) TrackingProtectionPolicy.strict() else
|
||||
TrackingProtectionPolicy.recommended()
|
||||
|
||||
return when {
|
||||
normalMode && privateMode -> trackingProtectionPolicy
|
||||
|
|
|
@ -8,6 +8,8 @@ import android.content.Context
|
|||
import android.view.ViewGroup
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.Navigation
|
||||
import com.airbnb.lottie.LottieCompositionFactory
|
||||
import com.airbnb.lottie.LottieDrawable
|
||||
import androidx.navigation.fragment.FragmentNavigator
|
||||
import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
|
@ -20,6 +22,7 @@ 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.nav
|
||||
|
@ -53,6 +56,26 @@ class ToolbarIntegration(
|
|||
return@run
|
||||
}
|
||||
|
||||
val task = LottieCompositionFactory
|
||||
.fromRawRes(
|
||||
context,
|
||||
ThemeManager.resolveAttribute(R.attr.shieldLottieFile, context)
|
||||
)
|
||||
task.addListener { result ->
|
||||
val lottieDrawable = LottieDrawable()
|
||||
lottieDrawable.composition = result
|
||||
toolbar.displayTrackingProtectionIcon =
|
||||
context.settings.shouldUseTrackingProtection && FeatureFlags.etpCategories
|
||||
toolbar.displaySeparatorView =
|
||||
context.settings.shouldUseTrackingProtection && FeatureFlags.etpCategories
|
||||
|
||||
toolbar.setTrackingProtectionIcons(
|
||||
iconOnNoTrackersBlocked = context.getDrawable(R.drawable.ic_tracking_protection_enabled)!!,
|
||||
iconOnTrackersBlocked = lottieDrawable,
|
||||
iconDisabledForSite = context.getDrawable(R.drawable.ic_tracking_protection_disabled)!!
|
||||
)
|
||||
}
|
||||
|
||||
val tabsAction = TabCounterToolbarButton(
|
||||
sessionManager,
|
||||
{
|
||||
|
|
|
@ -10,13 +10,18 @@ import android.view.Gravity
|
|||
import android.view.View
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import com.airbnb.lottie.LottieCompositionFactory
|
||||
import com.airbnb.lottie.LottieDrawable
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||
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
|
||||
import org.mozilla.fenix.theme.ThemeManager
|
||||
|
||||
class CustomTabsIntegration(
|
||||
context: Context,
|
||||
|
@ -50,6 +55,25 @@ class CustomTabsIntegration(
|
|||
|
||||
// Hide the Quick Action Bar.
|
||||
quickActionbar.visibility = View.GONE
|
||||
|
||||
val task = LottieCompositionFactory
|
||||
.fromRawRes(
|
||||
context,
|
||||
ThemeManager.resolveAttribute(R.attr.shieldLottieFile, context)
|
||||
)
|
||||
task.addListener { result ->
|
||||
val lottieDrawable = LottieDrawable()
|
||||
lottieDrawable.composition = result
|
||||
toolbar.displayTrackingProtectionIcon =
|
||||
context.settings.shouldUseTrackingProtection && FeatureFlags.etpCategories
|
||||
toolbar.displaySeparatorView = false
|
||||
|
||||
toolbar.setTrackingProtectionIcons(
|
||||
iconOnNoTrackersBlocked = context.getDrawable(R.drawable.ic_tracking_protection_enabled)!!,
|
||||
iconOnTrackersBlocked = lottieDrawable,
|
||||
iconDisabledForSite = context.getDrawable(R.drawable.ic_tracking_protection_disabled)!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val customTabToolbarMenu by lazy {
|
||||
|
|
|
@ -78,6 +78,18 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
nav(R.id.externalAppBrowserFragment, directions)
|
||||
}
|
||||
|
||||
override fun navToTrackingProtectionPanel(session: Session) {
|
||||
val directions =
|
||||
ExternalAppBrowserFragmentDirections
|
||||
.actionExternalAppBrowserFragmentToTrackingProtectionPanelDialogFragment(
|
||||
sessionId = session.id,
|
||||
url = session.url,
|
||||
trackingProtectionEnabled = session.trackerBlockingEnabled,
|
||||
gravity = getAppropriateLayoutGravity()
|
||||
)
|
||||
nav(R.id.externalAppBrowserFragment, directions)
|
||||
}
|
||||
|
||||
override fun getEngineMargins(): Pair<Int, Int> {
|
||||
val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height)
|
||||
return toolbarSize to 0
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* 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
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.res.TypedArrayUtils
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
|
||||
class RadioButtonInfoPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : RadioButtonPreference(context, attrs) {
|
||||
private var infoClickListener: (() -> Unit)? = null
|
||||
private var infoView: ImageView? = null
|
||||
|
||||
fun onInfoClickListener(listener: (() -> Unit)) {
|
||||
infoClickListener = listener
|
||||
}
|
||||
|
||||
override fun setEnabled(enabled: Boolean) {
|
||||
super.setEnabled(enabled)
|
||||
infoView?.alpha = if (enabled) FULL_ALPHA else HALF_ALPHA
|
||||
infoView?.isEnabled = enabled
|
||||
}
|
||||
|
||||
init {
|
||||
layoutResource = R.layout.preference_widget_radiobutton_with_info
|
||||
|
||||
context.withStyledAttributes(
|
||||
attrs,
|
||||
androidx.preference.R.styleable.Preference,
|
||||
TypedArrayUtils.getAttr(
|
||||
context,
|
||||
androidx.preference.R.attr.preferenceStyle,
|
||||
android.R.attr.preferenceStyle
|
||||
),
|
||||
0
|
||||
) {
|
||||
val defaultValue = when {
|
||||
hasValue(androidx.preference.R.styleable.Preference_defaultValue) ->
|
||||
getBoolean(androidx.preference.R.styleable.Preference_defaultValue, false)
|
||||
hasValue(androidx.preference.R.styleable.Preference_android_defaultValue) ->
|
||||
getBoolean(
|
||||
androidx.preference.R.styleable.Preference_android_defaultValue,
|
||||
false
|
||||
)
|
||||
else -> false
|
||||
}
|
||||
setDefaultValue(defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
infoView = holder.findViewById(R.id.info_button) as ImageView
|
||||
infoView?.increaseTapArea(EXTRA_TAP_AREA)
|
||||
infoView?.setOnClickListener {
|
||||
infoClickListener?.invoke()
|
||||
}
|
||||
infoView?.alpha = if (isEnabled) FULL_ALPHA else HALF_ALPHA
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_TAP_AREA = 22
|
||||
}
|
||||
}
|
|
@ -17,13 +17,14 @@ import androidx.preference.PreferenceViewHolder
|
|||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.settings
|
||||
|
||||
class RadioButtonPreference @JvmOverloads constructor(
|
||||
open class RadioButtonPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : Preference(context, attrs) {
|
||||
private val radioGroups = mutableListOf<RadioButtonPreference>()
|
||||
private lateinit var summaryView: TextView
|
||||
private lateinit var radioButton: RadioButton
|
||||
private var summaryView: TextView? = null
|
||||
private var titleView: TextView? = null
|
||||
private var radioButton: RadioButton? = null
|
||||
private var shouldSummaryBeParsedAsHtmlContent: Boolean = true
|
||||
private var defaultValue: Boolean = false
|
||||
private var clickListener: (() -> Unit)? = null
|
||||
|
@ -34,14 +35,21 @@ class RadioButtonPreference @JvmOverloads constructor(
|
|||
context.withStyledAttributes(
|
||||
attrs,
|
||||
androidx.preference.R.styleable.Preference,
|
||||
getAttr(context, androidx.preference.R.attr.preferenceStyle, android.R.attr.preferenceStyle),
|
||||
getAttr(
|
||||
context,
|
||||
androidx.preference.R.attr.preferenceStyle,
|
||||
android.R.attr.preferenceStyle
|
||||
),
|
||||
0
|
||||
) {
|
||||
defaultValue = when {
|
||||
hasValue(androidx.preference.R.styleable.Preference_defaultValue) ->
|
||||
getBoolean(androidx.preference.R.styleable.Preference_defaultValue, false)
|
||||
hasValue(androidx.preference.R.styleable.Preference_android_defaultValue) ->
|
||||
getBoolean(androidx.preference.R.styleable.Preference_android_defaultValue, false)
|
||||
getBoolean(
|
||||
androidx.preference.R.styleable.Preference_android_defaultValue,
|
||||
false
|
||||
)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +63,17 @@ class RadioButtonPreference @JvmOverloads constructor(
|
|||
clickListener = listener
|
||||
}
|
||||
|
||||
override fun setEnabled(enabled: Boolean) {
|
||||
super.setEnabled(enabled)
|
||||
if (!enabled) {
|
||||
summaryView?.alpha = HALF_ALPHA
|
||||
titleView?.alpha = HALF_ALPHA
|
||||
} else {
|
||||
summaryView?.alpha = FULL_ALPHA
|
||||
titleView?.alpha = FULL_ALPHA
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
|
||||
|
@ -75,44 +94,53 @@ class RadioButtonPreference @JvmOverloads constructor(
|
|||
|
||||
private fun updateRadioValue(isChecked: Boolean) {
|
||||
persistBoolean(isChecked)
|
||||
radioButton.isChecked = isChecked
|
||||
radioButton?.isChecked = isChecked
|
||||
context.settings.preferences.edit().putBoolean(key, isChecked)
|
||||
.apply()
|
||||
}
|
||||
|
||||
private fun bindRadioButton(holder: PreferenceViewHolder) {
|
||||
radioButton = holder.findViewById(R.id.radio_button) as RadioButton
|
||||
radioButton.isChecked = context.settings.preferences.getBoolean(key, false)
|
||||
radioButton.setStartCheckedIndicator()
|
||||
radioButton?.isChecked = context.settings.preferences.getBoolean(key, defaultValue)
|
||||
radioButton?.setStartCheckedIndicator()
|
||||
}
|
||||
|
||||
private fun toggleRadioGroups() {
|
||||
if (radioButton.isChecked) {
|
||||
if (radioButton?.isChecked == true) {
|
||||
radioGroups.forEach { it.updateRadioValue(false) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindTitle(holder: PreferenceViewHolder) {
|
||||
val titleView = holder.findViewById(R.id.title) as TextView
|
||||
titleView = holder.findViewById(R.id.title) as TextView
|
||||
titleView?.alpha = if (isEnabled) FULL_ALPHA else HALF_ALPHA
|
||||
|
||||
if (!title.isNullOrEmpty()) {
|
||||
titleView.text = title
|
||||
titleView?.text = title
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindSummaryView(holder: PreferenceViewHolder) {
|
||||
summaryView = holder.findViewById(R.id.widget_summary) as TextView
|
||||
|
||||
if (!summary.isNullOrEmpty()) {
|
||||
summaryView.text = if (shouldSummaryBeParsedAsHtmlContent) {
|
||||
HtmlCompat.fromHtml(summary.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT)
|
||||
} else {
|
||||
summary
|
||||
}
|
||||
summaryView?.alpha = if (isEnabled) FULL_ALPHA else HALF_ALPHA
|
||||
summaryView?.let {
|
||||
if (!summary.isNullOrEmpty()) {
|
||||
it.text = if (shouldSummaryBeParsedAsHtmlContent) {
|
||||
HtmlCompat.fromHtml(summary.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT)
|
||||
} else {
|
||||
summary
|
||||
}
|
||||
|
||||
summaryView.visibility = View.VISIBLE
|
||||
} else {
|
||||
summaryView.visibility = View.GONE
|
||||
it.visibility = View.VISIBLE
|
||||
} else {
|
||||
it.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HALF_ALPHA = 0.5F
|
||||
const val FULL_ALPHA = 1F
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@ import androidx.navigation.findNavController
|
|||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import org.mozilla.fenix.BrowserDirection
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.getPreferenceKey
|
||||
import org.mozilla.fenix.ext.nav
|
||||
import org.mozilla.fenix.ext.settings
|
||||
|
||||
/**
|
||||
|
@ -22,10 +25,13 @@ import org.mozilla.fenix.ext.settings
|
|||
class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private val exceptionsClickListener = Preference.OnPreferenceClickListener {
|
||||
val directions = TrackingProtectionFragmentDirections.actionTrackingProtectionFragmentToExceptionsFragment()
|
||||
val directions =
|
||||
TrackingProtectionFragmentDirections.actionTrackingProtectionFragmentToExceptionsFragment()
|
||||
view!!.findNavController().navigate(directions)
|
||||
true
|
||||
}
|
||||
private lateinit var radioStrict: RadioButtonInfoPreference
|
||||
private lateinit var radioStandard: RadioButtonInfoPreference
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.tracking_protection_preferences, rootKey)
|
||||
|
@ -33,7 +39,7 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
activity?.title = getString(R.string.preferences_tracking_protection)
|
||||
activity?.title = getString(R.string.preference_enhanced_tracking_protection)
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
|
||||
// Tracking Protection Switch
|
||||
|
@ -42,7 +48,8 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
|||
|
||||
preferenceTP?.isChecked = context!!.settings.shouldUseTrackingProtection
|
||||
preferenceTP?.setOnPreferenceChangeListener<Boolean> { preference, trackingProtectionOn ->
|
||||
preference.context.settings.shouldUseTrackingProtection = trackingProtectionOn
|
||||
preference.context.settings.shouldUseTrackingProtection =
|
||||
trackingProtectionOn
|
||||
with(preference.context.components) {
|
||||
val policy = core.createTrackingProtectionPolicy(trackingProtectionOn)
|
||||
useCases.settingsUseCases.updateTrackingProtection(policy)
|
||||
|
@ -51,8 +58,72 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
|||
true
|
||||
}
|
||||
|
||||
bindStrict()
|
||||
bindRecommended()
|
||||
setupRadioGroups()
|
||||
|
||||
val trackingProtectionLearnMore =
|
||||
context!!.getPreferenceKey(R.string.pref_key_etp_learn_more)
|
||||
val learnMorePreference = findPreference<Preference>(trackingProtectionLearnMore)
|
||||
learnMorePreference?.setOnPreferenceClickListener {
|
||||
(activity as HomeActivity).openToBrowserAndLoad(
|
||||
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic
|
||||
(SupportUtils.SumoTopic.TRACKING_PROTECTION),
|
||||
newTab = true,
|
||||
from = BrowserDirection.FromTrackingProtection
|
||||
)
|
||||
true
|
||||
}
|
||||
learnMorePreference?.summary = getString(
|
||||
R.string.preference_enhanced_tracking_protection_explanation,
|
||||
getString(R.string.app_name)
|
||||
)
|
||||
|
||||
val exceptions = getPreferenceKey(R.string.pref_key_tracking_protection_exceptions)
|
||||
val preferenceExceptions = findPreference<Preference>(exceptions)
|
||||
preferenceExceptions?.onPreferenceClickListener = exceptionsClickListener
|
||||
}
|
||||
|
||||
private fun bindStrict() {
|
||||
val keyStrict = getString(R.string.pref_key_tracking_protection_strict)
|
||||
radioStrict = requireNotNull(findPreference(keyStrict))
|
||||
radioStrict.onInfoClickListener {
|
||||
nav(
|
||||
R.id.trackingProtectionFragment,
|
||||
TrackingProtectionFragmentDirections
|
||||
.actionTrackingProtectionFragmentToTrackingProtectionBlockingFragment(true)
|
||||
)
|
||||
}
|
||||
radioStrict.onClickListener {
|
||||
updateTrackingProtectionPolicy()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindRecommended() {
|
||||
val keyStandard = getString(R.string.pref_key_tracking_protection_standard)
|
||||
radioStandard = requireNotNull(findPreference(keyStandard))
|
||||
radioStandard.onInfoClickListener {
|
||||
nav(
|
||||
R.id.trackingProtectionFragment,
|
||||
TrackingProtectionFragmentDirections
|
||||
.actionTrackingProtectionFragmentToTrackingProtectionBlockingFragment(false)
|
||||
)
|
||||
}
|
||||
radioStandard.onClickListener {
|
||||
updateTrackingProtectionPolicy()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTrackingProtectionPolicy() {
|
||||
context?.components?.let {
|
||||
val policy = it.core.createTrackingProtectionPolicy()
|
||||
it.useCases.settingsUseCases.updateTrackingProtection.invoke(policy)
|
||||
it.useCases.sessionUseCases.reload.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRadioGroups() {
|
||||
radioStandard.addToRadioGroup(radioStrict)
|
||||
radioStrict.addToRadioGroup(radioStandard)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,11 @@ import android.widget.CompoundButton
|
|||
import android.widget.Switch
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import io.reactivex.Observer
|
||||
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
||||
import org.mozilla.fenix.FeatureFlags
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.settings
|
||||
|
||||
|
@ -20,15 +22,23 @@ class TrackingProtectionSettingView(
|
|||
private val actionEmitter: Observer<QuickSettingsAction>
|
||||
) : View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
private val trackingProtectionSwitch: Switch = container.findViewById(R.id.tracking_protection)
|
||||
private val trackingProtectionAction: TextView = container.findViewById(R.id.tracking_protection_action)
|
||||
private val trackingProtectionAction: TextView =
|
||||
container.findViewById(R.id.tracking_protection_action)
|
||||
private val trackingProtectionSettingView: ConstraintLayout =
|
||||
container.findViewById(R.id.tracking_protection_view)
|
||||
|
||||
init {
|
||||
trackingProtectionSwitch.putCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
start = AppCompatResources.getDrawable(container.context, R.drawable.ic_tracking_protection)
|
||||
start = AppCompatResources.getDrawable(
|
||||
container.context,
|
||||
R.drawable.ic_tracking_protection
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun bind(isTrackingProtectionOn: Boolean) {
|
||||
trackingProtectionSettingView.visibility =
|
||||
if (FeatureFlags.etpCategories) View.GONE else View.VISIBLE
|
||||
val globalTPSetting = trackingProtectionSwitch.context.settings.shouldUseTrackingProtection
|
||||
|
||||
trackingProtectionAction.isVisible = !globalTPSetting
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* 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.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import kotlinx.android.synthetic.main.switch_with_description.view.*
|
||||
import kotlinx.android.synthetic.main.tracking_protection_category.view.switchItemDescription
|
||||
import kotlinx.android.synthetic.main.tracking_protection_category.view.switchItemTitle
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
class SwitchWithDescription @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs) {
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.switch_with_description, this, true)
|
||||
|
||||
context.withStyledAttributes(attrs, R.styleable.SwitchWithDescription, defStyleAttr, 0) {
|
||||
val id = getResourceId(
|
||||
R.styleable.SwitchWithDescription_switchIcon,
|
||||
R.drawable.ic_tracking_protection
|
||||
)
|
||||
switch_widget?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
resources.getDrawable(
|
||||
id,
|
||||
context.theme
|
||||
), null, null, null
|
||||
)
|
||||
switchItemTitle?.text = resources.getString(
|
||||
getResourceId(
|
||||
R.styleable.SwitchWithDescription_switchTitle,
|
||||
R.string.preference_enhanced_tracking_protection
|
||||
)
|
||||
)
|
||||
switchItemDescription?.text = resources.getString(
|
||||
getResourceId(
|
||||
R.styleable.SwitchWithDescription_switchDescription,
|
||||
R.string.preference_enhanced_tracking_protection_explanation
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* 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.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.android.synthetic.main.fragment_tracking_protection_blocking.*
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
class TrackingProtectionBlockingFragment : Fragment() {
|
||||
private val safeArguments get() = requireNotNull(arguments)
|
||||
|
||||
private val isStrict: Boolean by lazy {
|
||||
TrackingProtectionBlockingFragmentArgs.fromBundle(safeArguments).strictMode
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_tracking_protection_blocking, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (isStrict) {
|
||||
category_tracking_content.visibility = View.VISIBLE
|
||||
} else {
|
||||
category_tracking_content.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(activity as AppCompatActivity).title =
|
||||
getString(
|
||||
if (isStrict) R.string.preference_enhanced_tracking_protection_strict else
|
||||
R.string.preference_enhanced_tracking_protection_standard
|
||||
)
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* 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.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import kotlinx.android.synthetic.main.tracking_protection_category.view.*
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
class TrackingProtectionCategoryItem @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.tracking_protection_category, this, true)
|
||||
|
||||
context.withStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.TrackingProtectionCategory,
|
||||
defStyleAttr,
|
||||
0
|
||||
) {
|
||||
val id = getResourceId(
|
||||
R.styleable.TrackingProtectionCategory_categoryItemIcon,
|
||||
R.drawable.ic_cryptominers
|
||||
)
|
||||
switchIcon?.background = resources.getDrawable(id, context.theme)
|
||||
switchItemTitle?.text = resources.getString(
|
||||
getResourceId(
|
||||
R.styleable.TrackingProtectionCategory_categoryItemTitle,
|
||||
R.string.etp_cookies_title
|
||||
)
|
||||
)
|
||||
switchItemDescription?.text = resources.getString(
|
||||
getResourceId(
|
||||
R.styleable.TrackingProtectionCategory_categoryItemDescription,
|
||||
R.string.etp_cookies_description
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/* 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.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.whenStarted
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import kotlinx.android.synthetic.main.fragment_tracking_protection.view.*
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.concept.engine.content.blocking.Tracker
|
||||
import mozilla.components.lib.state.ext.observe
|
||||
import mozilla.components.support.base.feature.BackHandler
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.components.StoreProvider
|
||||
import org.mozilla.fenix.exceptions.ExceptionDomains
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.nav
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
|
||||
class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), BackHandler {
|
||||
|
||||
private val safeArguments get() = requireNotNull(arguments)
|
||||
|
||||
private val sessionId: String by lazy {
|
||||
TrackingProtectionPanelDialogFragmentArgs.fromBundle(
|
||||
safeArguments
|
||||
).sessionId
|
||||
}
|
||||
|
||||
private val url: String by lazy {
|
||||
TrackingProtectionPanelDialogFragmentArgs.fromBundle(safeArguments).url
|
||||
}
|
||||
|
||||
private val trackingProtectionEnabled: Boolean by lazy {
|
||||
TrackingProtectionPanelDialogFragmentArgs.fromBundle(safeArguments)
|
||||
.trackingProtectionEnabled
|
||||
}
|
||||
|
||||
private val promptGravity: Int by lazy {
|
||||
TrackingProtectionPanelDialogFragmentArgs.fromBundle(
|
||||
safeArguments
|
||||
).gravity
|
||||
}
|
||||
|
||||
private fun inflateRootView(container: ViewGroup? = null): View {
|
||||
val contextThemeWrapper = ContextThemeWrapper(
|
||||
activity,
|
||||
(activity as HomeActivity).themeManager.currentThemeResource
|
||||
)
|
||||
return LayoutInflater.from(contextThemeWrapper).inflate(
|
||||
R.layout.fragment_tracking_protection,
|
||||
container,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
private lateinit var trackingProtectionStore: TrackingProtectionStore
|
||||
private lateinit var trackingProtectionView: TrackingProtectionPanelView
|
||||
private lateinit var trackingProtectionInteractor: TrackingProtectionPanelInteractor
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflateRootView(container)
|
||||
val session = requireComponents.core.sessionManager.findSessionById(sessionId)
|
||||
session?.register(sessionObserver, view = view)
|
||||
trackingProtectionStore = StoreProvider.get(this) {
|
||||
TrackingProtectionStore(
|
||||
TrackingProtectionState(
|
||||
url,
|
||||
trackingProtectionEnabled,
|
||||
session?.trackersBlocked ?: listOf(),
|
||||
session?.trackersLoaded ?: listOf(),
|
||||
TrackingProtectionState.Mode.Normal
|
||||
)
|
||||
)
|
||||
}
|
||||
trackingProtectionInteractor = TrackingProtectionPanelInteractor(
|
||||
trackingProtectionStore,
|
||||
::toggleTrackingProtection,
|
||||
::openTrackingProtectionSettings
|
||||
)
|
||||
trackingProtectionView =
|
||||
TrackingProtectionPanelView(view.fragment_tp, trackingProtectionInteractor)
|
||||
return view
|
||||
}
|
||||
|
||||
private val sessionObserver = object : Session.Observer {
|
||||
override fun onUrlChanged(session: Session, url: String) {
|
||||
trackingProtectionStore.dispatch(
|
||||
TrackingProtectionAction.UrlChange(url)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTrackerBlocked(session: Session, tracker: Tracker, all: List<Tracker>) {
|
||||
trackingProtectionStore.dispatch(
|
||||
TrackingProtectionAction.TrackerListChange(all)
|
||||
)
|
||||
trackingProtectionStore.dispatch(
|
||||
TrackingProtectionAction.TrackerLoadedListChange(session.trackersLoaded)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTrackerLoaded(session: Session, tracker: Tracker, all: List<Tracker>) {
|
||||
trackingProtectionStore.dispatch(
|
||||
TrackingProtectionAction.TrackerListChange(session.trackersBlocked)
|
||||
)
|
||||
trackingProtectionStore.dispatch(
|
||||
TrackingProtectionAction.TrackerLoadedListChange(all)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
trackingProtectionStore.observe(view) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
whenStarted {
|
||||
trackingProtectionView.update(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openTrackingProtectionSettings() {
|
||||
nav(
|
||||
R.id.trackingProtectionPanelDialogFragment,
|
||||
TrackingProtectionPanelDialogFragmentDirections
|
||||
.actionTrackingProtectionPanelDialogFragmentToTrackingProtectionFragment()
|
||||
)
|
||||
}
|
||||
|
||||
private fun toggleTrackingProtection(isEnabled: Boolean) {
|
||||
context?.let {
|
||||
val host = try {
|
||||
URL(url).host
|
||||
} catch (e: MalformedURLException) {
|
||||
url
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
if (!ExceptionDomains.load(it).contains(host)) {
|
||||
ExceptionDomains.add(it, host)
|
||||
} else {
|
||||
ExceptionDomains.remove(it, listOf(host))
|
||||
}
|
||||
}
|
||||
it.components.useCases.sessionUseCases.reload.invoke()
|
||||
}
|
||||
trackingProtectionStore.dispatch(TrackingProtectionAction.TrackerBlockingChanged(isEnabled))
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return if (promptGravity == Gravity.BOTTOM) {
|
||||
object : BottomSheetDialog(requireContext(), this.theme) {
|
||||
override fun onBackPressed() {
|
||||
this@TrackingProtectionPanelDialogFragment.onBackPressed()
|
||||
}
|
||||
}.apply {
|
||||
setOnShowListener {
|
||||
val bottomSheet =
|
||||
findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as? FrameLayout
|
||||
val behavior = BottomSheetBehavior.from(bottomSheet)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object : Dialog(requireContext()) {
|
||||
override fun onBackPressed() {
|
||||
this@TrackingProtectionPanelDialogFragment.onBackPressed()
|
||||
}
|
||||
}.applyCustomizationsForTopDialog(inflateRootView())
|
||||
}
|
||||
}
|
||||
|
||||
private fun Dialog.applyCustomizationsForTopDialog(rootView: View): Dialog {
|
||||
addContentView(
|
||||
rootView,
|
||||
LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
)
|
||||
|
||||
window?.apply {
|
||||
setGravity(promptGravity)
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
// This must be called after addContentView, or it won't fully fill to the edge.
|
||||
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean = trackingProtectionView.onBackPressed()
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* 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
|
||||
|
||||
/**
|
||||
* Interactor for the tracking protection panel
|
||||
* Provides implementations for the TrackingProtectionPanelViewInteractor
|
||||
*/
|
||||
class TrackingProtectionPanelInteractor(
|
||||
private val store: TrackingProtectionStore,
|
||||
private val toggleTrackingProtection: (Boolean) -> Unit,
|
||||
private val openTrackingProtectionSettings: () -> Unit
|
||||
) : TrackingProtectionPanelViewInteractor {
|
||||
override fun openDetails(category: TrackingProtectionCategory, categoryBlocked: Boolean) {
|
||||
store.dispatch(TrackingProtectionAction.EnterDetailsMode(category, categoryBlocked))
|
||||
}
|
||||
|
||||
override fun selectTrackingProtectionSettings() {
|
||||
openTrackingProtectionSettings.invoke()
|
||||
}
|
||||
|
||||
override fun trackingProtectionToggled(isEnabled: Boolean) {
|
||||
toggleTrackingProtection.invoke(isEnabled)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
store.dispatch(TrackingProtectionAction.ExitDetailsMode)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
/* 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.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.net.toUri
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.component_tracking_protection_panel.*
|
||||
import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.url
|
||||
import kotlinx.android.synthetic.main.switch_with_description.view.*
|
||||
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.CRYPTOMINING
|
||||
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.FINGERPRINTING
|
||||
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.SOCIAL
|
||||
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.AD
|
||||
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.TrackingCategory.ANALYTICS
|
||||
import mozilla.components.concept.engine.content.blocking.Tracker
|
||||
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.getHostFromUrl
|
||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CROSS_SITE_TRACKING_COOKIES
|
||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.CRYPTOMINERS
|
||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.FINGERPRINTERS
|
||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.SOCIAL_MEDIA_TRACKERS
|
||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.TRACKING_CONTENT
|
||||
|
||||
/**
|
||||
* Interface for the TrackingProtectionPanelViewInteractor. This interface is implemented by objects that want
|
||||
* to respond to user interaction on the TrackingProtectionPanelView
|
||||
*/
|
||||
interface TrackingProtectionPanelViewInteractor {
|
||||
/**
|
||||
* Called whenever the settings option is tapped
|
||||
*/
|
||||
fun selectTrackingProtectionSettings()
|
||||
|
||||
/**
|
||||
* Called whenever the tracking protection toggle for this site is toggled
|
||||
* @param isEnabled new status of session tracking protection
|
||||
*/
|
||||
fun trackingProtectionToggled(isEnabled: Boolean)
|
||||
|
||||
/**
|
||||
* Called whenever back is pressed
|
||||
*/
|
||||
fun onBackPressed()
|
||||
|
||||
/**
|
||||
* Called whenever an active tracking protection category is tapped
|
||||
* @param category The Tracking Protection Category to view details about
|
||||
* @param categoryBlocked The trackers from this category were blocked
|
||||
*/
|
||||
fun openDetails(category: TrackingProtectionCategory, categoryBlocked: Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* View that contains and configures the Tracking Protection Panel
|
||||
*/
|
||||
class TrackingProtectionPanelView(
|
||||
override val containerView: ViewGroup,
|
||||
val interactor: TrackingProtectionPanelInteractor
|
||||
) : LayoutContainer {
|
||||
val view: ConstraintLayout = LayoutInflater.from(containerView.context)
|
||||
.inflate(R.layout.component_tracking_protection_panel, containerView, true)
|
||||
.findViewById(R.id.panel_wrapper)
|
||||
|
||||
private val context get() = view.context
|
||||
|
||||
var mode: TrackingProtectionState.Mode = TrackingProtectionState.Mode.Normal
|
||||
private set
|
||||
|
||||
var trackers: List<Tracker> = listOf()
|
||||
private set
|
||||
|
||||
var bucketedTrackers: HashMap<TrackingProtectionCategory, List<String>> = HashMap()
|
||||
|
||||
var loadedTrackers: List<Tracker> = listOf()
|
||||
private set
|
||||
|
||||
var bucketedLoadedTrackers: HashMap<TrackingProtectionCategory, List<String>> = HashMap()
|
||||
|
||||
fun update(state: TrackingProtectionState) {
|
||||
if (state.mode != mode) {
|
||||
mode = state.mode
|
||||
}
|
||||
|
||||
if (state.listTrackers != trackers) {
|
||||
trackers = state.listTrackers
|
||||
bucketedTrackers = getHashMapOfTrackersForCategory(state.listTrackers)
|
||||
}
|
||||
|
||||
if (state.listTrackersLoaded != loadedTrackers) {
|
||||
loadedTrackers = state.listTrackersLoaded
|
||||
bucketedLoadedTrackers = getHashMapOfTrackersForCategory(state.listTrackersLoaded)
|
||||
}
|
||||
|
||||
when (val mode = state.mode) {
|
||||
is TrackingProtectionState.Mode.Normal -> setUIForNormalMode(state)
|
||||
is TrackingProtectionState.Mode.Details -> setUIForDetailsMode(
|
||||
mode.selectedCategory,
|
||||
mode.categoryBlocked
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUIForNormalMode(state: TrackingProtectionState) {
|
||||
details_mode.visibility = View.GONE
|
||||
normal_mode.visibility = View.VISIBLE
|
||||
|
||||
not_blocking_header.visibility =
|
||||
if (bucketedLoadedTrackers.size == 0) View.GONE else View.VISIBLE
|
||||
bindUrl(state.url)
|
||||
bindTrackingProtectionInfo(state.isTrackingProtectionEnabled)
|
||||
protection_settings.setOnClickListener {
|
||||
interactor.selectTrackingProtectionSettings()
|
||||
}
|
||||
|
||||
blocking_header.visibility =
|
||||
if (bucketedTrackers.size == 0) View.GONE else View.VISIBLE
|
||||
updateCategoryVisibility()
|
||||
setCategoryClickListeners()
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
private fun updateCategoryVisibility() {
|
||||
cross_site_tracking.visibility = bucketedTrackers.getVisibility(CROSS_SITE_TRACKING_COOKIES)
|
||||
social_media_trackers.visibility = bucketedTrackers.getVisibility(SOCIAL_MEDIA_TRACKERS)
|
||||
fingerprinters.visibility = bucketedTrackers.getVisibility(FINGERPRINTERS)
|
||||
tracking_content.visibility = bucketedTrackers.getVisibility(TRACKING_CONTENT)
|
||||
cryptominers.visibility = bucketedTrackers.getVisibility(CRYPTOMINERS)
|
||||
|
||||
cross_site_tracking_loaded.visibility =
|
||||
bucketedLoadedTrackers.getVisibility(CROSS_SITE_TRACKING_COOKIES)
|
||||
social_media_trackers_loaded.visibility =
|
||||
bucketedLoadedTrackers.getVisibility(SOCIAL_MEDIA_TRACKERS)
|
||||
fingerprinters_loaded.visibility = bucketedLoadedTrackers.getVisibility(FINGERPRINTERS)
|
||||
tracking_content_loaded.visibility = bucketedLoadedTrackers.getVisibility(TRACKING_CONTENT)
|
||||
cryptominers_loaded.visibility = bucketedLoadedTrackers.getVisibility(CRYPTOMINERS)
|
||||
}
|
||||
|
||||
private fun HashMap<TrackingProtectionCategory, List<String>>.getVisibility(
|
||||
category: TrackingProtectionCategory
|
||||
): Int = if (this[category]?.isNotEmpty() == true) View.VISIBLE else View.GONE
|
||||
|
||||
private fun setCategoryClickListeners() {
|
||||
social_media_trackers.setOnClickListener {
|
||||
interactor.openDetails(SOCIAL_MEDIA_TRACKERS, categoryBlocked = true)
|
||||
}
|
||||
fingerprinters.setOnClickListener {
|
||||
interactor.openDetails(FINGERPRINTERS, categoryBlocked = true)
|
||||
}
|
||||
cross_site_tracking.setOnClickListener {
|
||||
interactor.openDetails(CROSS_SITE_TRACKING_COOKIES, categoryBlocked = true)
|
||||
}
|
||||
tracking_content.setOnClickListener {
|
||||
interactor.openDetails(TRACKING_CONTENT, categoryBlocked = true)
|
||||
}
|
||||
cryptominers.setOnClickListener {
|
||||
interactor.openDetails(CRYPTOMINERS, categoryBlocked = true)
|
||||
}
|
||||
social_media_trackers_loaded.setOnClickListener {
|
||||
interactor.openDetails(SOCIAL_MEDIA_TRACKERS, categoryBlocked = false)
|
||||
}
|
||||
fingerprinters_loaded.setOnClickListener {
|
||||
interactor.openDetails(FINGERPRINTERS, categoryBlocked = false)
|
||||
}
|
||||
cross_site_tracking_loaded.setOnClickListener {
|
||||
interactor.openDetails(CROSS_SITE_TRACKING_COOKIES, categoryBlocked = false)
|
||||
}
|
||||
tracking_content_loaded.setOnClickListener {
|
||||
interactor.openDetails(TRACKING_CONTENT, categoryBlocked = false)
|
||||
}
|
||||
cryptominers_loaded.setOnClickListener {
|
||||
interactor.openDetails(CRYPTOMINERS, categoryBlocked = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUIForDetailsMode(
|
||||
category: TrackingProtectionCategory,
|
||||
categoryBlocked: Boolean
|
||||
) {
|
||||
normal_mode.visibility = View.GONE
|
||||
details_mode.visibility = View.VISIBLE
|
||||
category_title.text = context.getString(category.title)
|
||||
val stringList = bucketedTrackers[category]?.joinToString("\n")
|
||||
blocking_text_list.text = stringList
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getHashMapOfTrackersForCategory(
|
||||
list: List<Tracker>
|
||||
): HashMap<TrackingProtectionCategory, List<String>> {
|
||||
val hashMap = HashMap<TrackingProtectionCategory, List<String>>()
|
||||
items@ for (item in list) {
|
||||
when {
|
||||
item.trackingCategories.contains(CRYPTOMINING) -> {
|
||||
hashMap[CRYPTOMINERS] =
|
||||
(hashMap[CRYPTOMINERS]
|
||||
?: listOf()).plus(item.url.getHostFromUrl() ?: item.url)
|
||||
continue@items
|
||||
}
|
||||
item.trackingCategories.contains(FINGERPRINTING) -> {
|
||||
hashMap[FINGERPRINTERS] =
|
||||
(hashMap[FINGERPRINTERS]
|
||||
?: listOf()).plus(item.url.getHostFromUrl() ?: item.url)
|
||||
continue@items
|
||||
}
|
||||
item.trackingCategories.contains(SOCIAL) -> {
|
||||
hashMap[SOCIAL_MEDIA_TRACKERS] =
|
||||
(hashMap[SOCIAL_MEDIA_TRACKERS] ?: listOf()).plus(
|
||||
item.url.getHostFromUrl() ?: item.url
|
||||
)
|
||||
continue@items
|
||||
}
|
||||
item.trackingCategories.contains(AD) ||
|
||||
item.trackingCategories.contains(SOCIAL) ||
|
||||
item.trackingCategories.contains(ANALYTICS) -> {
|
||||
hashMap[TRACKING_CONTENT] =
|
||||
(hashMap[TRACKING_CONTENT] ?: listOf()).plus(
|
||||
item.url.getHostFromUrl() ?: item.url
|
||||
)
|
||||
continue@items
|
||||
}
|
||||
}
|
||||
}
|
||||
return hashMap
|
||||
}
|
||||
|
||||
private fun bindUrl(url: String) {
|
||||
this.url.text = url.toUri().hostWithoutCommonPrefixes
|
||||
}
|
||||
|
||||
private fun bindTrackingProtectionInfo(isTrackingProtectionOn: Boolean) {
|
||||
tracking_protection.switchItemDescription.text =
|
||||
context.getString(if (isTrackingProtectionOn) R.string.etp_panel_on else R.string.etp_panel_off)
|
||||
tracking_protection.switch_widget.isChecked = isTrackingProtectionOn
|
||||
|
||||
tracking_protection.switch_widget.setOnCheckedChangeListener { _, isChecked ->
|
||||
interactor.trackingProtectionToggled(isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
fun onBackPressed(): Boolean {
|
||||
return when (mode) {
|
||||
is TrackingProtectionState.Mode.Details -> {
|
||||
mode = TrackingProtectionState.Mode.Normal
|
||||
interactor.onBackPressed()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/* 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 mozilla.components.concept.engine.content.blocking.Tracker
|
||||
import mozilla.components.lib.state.Action
|
||||
import mozilla.components.lib.state.State
|
||||
import mozilla.components.lib.state.Store
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
/**
|
||||
* The [Store] for holding the [TrackingProtectionState] and applying [TrackingProtectionAction]s.
|
||||
*/
|
||||
class TrackingProtectionStore(initialState: TrackingProtectionState) :
|
||||
Store<TrackingProtectionState, TrackingProtectionAction>(
|
||||
initialState,
|
||||
::trackingProtectionStateReducer
|
||||
)
|
||||
|
||||
/**
|
||||
* Actions to dispatch through the `TrackingProtectionStore` to modify `TrackingProtectionState` through the reducer.
|
||||
*/
|
||||
sealed class TrackingProtectionAction : Action {
|
||||
data class Change(
|
||||
val url: String,
|
||||
val isTrackingProtectionEnabled: Boolean,
|
||||
val listTrackers: List<Tracker>,
|
||||
val listTrackersLoaded: List<Tracker>,
|
||||
val mode: TrackingProtectionState.Mode
|
||||
) : TrackingProtectionAction()
|
||||
|
||||
data class UrlChange(val url: String) : TrackingProtectionAction()
|
||||
data class TrackerListChange(val listTrackers: List<Tracker>) : TrackingProtectionAction()
|
||||
data class TrackerLoadedListChange(val listTrackersLoaded: List<Tracker>) :
|
||||
TrackingProtectionAction()
|
||||
|
||||
data class TrackerBlockingChanged(val isTrackingProtectionEnabled: Boolean) :
|
||||
TrackingProtectionAction()
|
||||
|
||||
object ExitDetailsMode : TrackingProtectionAction()
|
||||
data class EnterDetailsMode(
|
||||
val category: TrackingProtectionCategory,
|
||||
val categoryBlocked: Boolean
|
||||
) :
|
||||
TrackingProtectionAction()
|
||||
}
|
||||
|
||||
/**
|
||||
* The state for the Tracking Protection Panel
|
||||
* @property url Current URL to display
|
||||
* @property isTrackingProtectionEnabled Current status of tracking protection for this session (ie is an exception)
|
||||
* @property listTrackers List of currently blocked Trackers
|
||||
* @property listTrackersLoaded List of currently not blocked Trackers
|
||||
* @property mode Current Mode of TrackingProtection
|
||||
*/
|
||||
data class TrackingProtectionState(
|
||||
val url: String,
|
||||
val isTrackingProtectionEnabled: Boolean,
|
||||
val listTrackers: List<Tracker>,
|
||||
val listTrackersLoaded: List<Tracker>,
|
||||
val mode: Mode
|
||||
) : State {
|
||||
sealed class Mode {
|
||||
object Normal : Mode()
|
||||
data class Details(
|
||||
val selectedCategory: TrackingProtectionCategory,
|
||||
val categoryBlocked: Boolean
|
||||
) : Mode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The 5 categories of Tracking Protection to display
|
||||
*/
|
||||
enum class TrackingProtectionCategory(val title: Int, val description: Int) {
|
||||
SOCIAL_MEDIA_TRACKERS(
|
||||
R.string.etp_social_media_trackers_title,
|
||||
R.string.etp_social_media_trackers_description
|
||||
),
|
||||
CROSS_SITE_TRACKING_COOKIES(
|
||||
R.string.etp_cookies_title,
|
||||
R.string.etp_cookies_description
|
||||
),
|
||||
CRYPTOMINERS(
|
||||
R.string.etp_cryptominers_title,
|
||||
R.string.etp_cryptominers_description
|
||||
),
|
||||
FINGERPRINTERS(R.string.etp_fingerprinters_title, R.string.etp_fingerprinters_description),
|
||||
TRACKING_CONTENT(R.string.etp_tracking_content_title, R.string.etp_tracking_content_description)
|
||||
}
|
||||
|
||||
/**
|
||||
* The TrackingProtectionState Reducer.
|
||||
*/
|
||||
fun trackingProtectionStateReducer(
|
||||
state: TrackingProtectionState,
|
||||
action: TrackingProtectionAction
|
||||
): TrackingProtectionState {
|
||||
return when (action) {
|
||||
is TrackingProtectionAction.Change -> state.copy(
|
||||
url = action.url,
|
||||
isTrackingProtectionEnabled = action.isTrackingProtectionEnabled,
|
||||
listTrackers = action.listTrackers,
|
||||
mode = action.mode
|
||||
)
|
||||
is TrackingProtectionAction.UrlChange -> state.copy(
|
||||
url = action.url
|
||||
)
|
||||
is TrackingProtectionAction.TrackerListChange -> state.copy(
|
||||
listTrackers = action.listTrackers
|
||||
)
|
||||
is TrackingProtectionAction.TrackerLoadedListChange -> state.copy(
|
||||
listTrackersLoaded = action.listTrackersLoaded
|
||||
)
|
||||
TrackingProtectionAction.ExitDetailsMode -> state.copy(
|
||||
mode = TrackingProtectionState.Mode.Normal
|
||||
)
|
||||
is TrackingProtectionAction.EnterDetailsMode -> state.copy(
|
||||
mode = TrackingProtectionState.Mode.Details(
|
||||
action.category,
|
||||
action.categoryBlocked
|
||||
)
|
||||
)
|
||||
is TrackingProtectionAction.TrackerBlockingChanged ->
|
||||
state.copy(isTrackingProtectionEnabled = action.isTrackingProtectionEnabled)
|
||||
}
|
||||
}
|
|
@ -29,9 +29,9 @@ class Settings private constructor(
|
|||
context: Context,
|
||||
private val isCrashReportEnabledInBuild: Boolean
|
||||
) : PreferencesHolder {
|
||||
|
||||
companion object {
|
||||
const val autoBounceMaximumCount = 2
|
||||
const val trackingProtectionOnboardingMaximumCount = 2
|
||||
const val FENIX_PREFERENCES = "fenix_preferences"
|
||||
private const val BLOCKED_INT = 0
|
||||
private const val ASK_TO_ALLOW_INT = 1
|
||||
|
@ -80,7 +80,10 @@ class Settings private constructor(
|
|||
|
||||
val isCrashReportingEnabled: Boolean
|
||||
get() = isCrashReportEnabledInBuild &&
|
||||
preferences.getBoolean(appContext.getPreferenceKey(R.string.pref_key_crash_reporter), true)
|
||||
preferences.getBoolean(
|
||||
appContext.getPreferenceKey(R.string.pref_key_crash_reporter),
|
||||
true
|
||||
)
|
||||
|
||||
val isRemoteDebuggingEnabled by booleanPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_remote_debugging),
|
||||
|
@ -97,6 +100,12 @@ class Settings private constructor(
|
|||
default = true
|
||||
)
|
||||
|
||||
private var trackingProtectionOnboardingShownThisSession = false
|
||||
|
||||
val shouldShowTrackingProtectionOnboarding: Boolean
|
||||
get() = trackingProtectionOnboardingCount < trackingProtectionOnboardingMaximumCount &&
|
||||
!trackingProtectionOnboardingShownThisSession
|
||||
|
||||
val shouldAutoBounceQuickActionSheet: Boolean
|
||||
get() = autoBounceQuickActionSheetCount < autoBounceMaximumCount
|
||||
|
||||
|
@ -150,6 +159,11 @@ class Settings private constructor(
|
|||
default = false
|
||||
)
|
||||
|
||||
val useStrictTrackingProtection by booleanPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict),
|
||||
false
|
||||
)
|
||||
|
||||
val themeSettingString: String
|
||||
get() = when {
|
||||
shouldFollowDeviceTheme -> appContext.getString(R.string.preference_follow_device_theme)
|
||||
|
@ -177,10 +191,27 @@ class Settings private constructor(
|
|||
default = true
|
||||
)
|
||||
|
||||
@VisibleForTesting(otherwise = PRIVATE)
|
||||
internal val trackingProtectionOnboardingCount by intPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_onboarding),
|
||||
0
|
||||
)
|
||||
|
||||
fun incrementTrackingProtectionOnboardingCount() {
|
||||
trackingProtectionOnboardingShownThisSession = true
|
||||
preferences.edit().putInt(
|
||||
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_onboarding),
|
||||
trackingProtectionOnboardingCount + 1
|
||||
).apply()
|
||||
}
|
||||
|
||||
fun getSitePermissionsPhoneFeatureAction(feature: PhoneFeature) =
|
||||
intToAction(preferences.getInt(feature.getPreferenceKey(appContext), ASK_TO_ALLOW_INT))
|
||||
|
||||
fun setSitePermissionsPhoneFeatureAction(feature: PhoneFeature, value: SitePermissionsRules.Action) {
|
||||
fun setSitePermissionsPhoneFeatureAction(
|
||||
feature: PhoneFeature,
|
||||
value: SitePermissionsRules.Action
|
||||
) {
|
||||
preferences.edit().putInt(feature.getPreferenceKey(appContext), actionToInt(value)).apply()
|
||||
}
|
||||
|
||||
|
@ -212,5 +243,8 @@ class Settings private constructor(
|
|||
}
|
||||
|
||||
val searchWidgetInstalled: Boolean
|
||||
get() = 0 < preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_search_widget_installed), 0)
|
||||
get() = 0 < preferences.getInt(
|
||||
appContext.getPreferenceKey(R.string.pref_key_search_widget_installed),
|
||||
0
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!-- 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/. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="7"
|
||||
android:viewportHeight="13">
|
||||
<path
|
||||
android:fillColor="?primaryText"
|
||||
android:pathData="M0.9998,12.4877C0.5954,12.4877 0.2309,12.244 0.0761,11.8704C-0.0786,11.4967 0.0069,11.0667 0.2928,10.7807L4.5858,6.4877L0.2928,2.1947C-0.0862,1.8023 -0.0807,1.1786 0.305,0.7929C0.6907,0.4072 1.3144,0.4017 1.7068,0.7807L6.7068,5.7807C7.0972,6.1712 7.0972,6.8042 6.7068,7.1947L1.7068,12.1947C1.5193,12.3823 1.265,12.4877 0.9998,12.4877Z" />
|
||||
</vector>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?primaryText"
|
||||
android:pathData="M11,4V3a1,1 0,0 1,2 0v1h6v5h-6v12a1,1 0,0 1,-2 0V9H5.4C4.2,9 3.6,7.8 4.3,7l1.6,-2c0.5,-0.6 1.3,-1 2.2,-1H11z"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -7,7 +7,7 @@
|
|||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12 22a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm0-18a8 8 0 1 0 0 16 8 8 0 0 0 0-16zm0 7c0.6 0 1 0.4 1 1v4a1 1 0 0 1-2 0v-4c0-0.6 0.4-1 1-1zm0-4a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"
|
||||
android:fillColor="?primaryText" />
|
||||
<path
|
||||
android:fillColor="?primaryText"
|
||||
android:pathData="M12 22a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm0-18a8 8 0 1 0 0 16 8 8 0 0 0 0-16zm0 7c0.6 0 1 0.4 1 1v4a1 1 0 0 1-2 0v-4c0-0.6 0.4-1 1-1zm0-4a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" />
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/primaryText"
|
||||
android:pathData="M20.9,8.4c0.6,-1.3 0.1,-2.4 -0.8,-3.3 0.3,-1.8 -0.9,-2.5 -2.8,-3 -0.5,-0.2 -2.5,0 -3.3,0l-6,0.3C6,2.4 3.8,2 1.7,2v8.6h4.3c0.3,0.1 1,0.8 1.1,1 0.2,0.1 0.2,0.3 0.2,0.3s0.4,1 0.8,1.3c1.6,1.6 2.9,4.5 3.5,6.8 0.5,0.7 -1,1.8 0.9,2 1.7,0.2 2.4,-3 1.8,-4.3 -0.6,-1.3 -1.2,-3.8 0,-3.5l1,0.2c1.6,0.5 4,0.7 5.3,-0.1 1.2,-0.9 0.6,-1.6 0.4,-2.6 1,-1 0.8,-2.2 0,-3.3" />
|
||||
</vector>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/primaryText"
|
||||
android:pathData="M19,21L5,21a3,3 0,0 1,-3 -3L2,6a3,3 0,0 1,3 -3h14a3,3 0,0 1,3 3v12a3,3 0,0 1,-3 3zM19,5L5,5a1,1 0,0 0,-1 1v12c0,0.6 0.4,1 1,1h14c0.6,0 1,-0.4 1,-1L20,6c0,-0.6 -0.4,-1 -1,-1zM18,17L6,17v-2c0,-0.2 0,-0.4 0.2,-0.5l2.5,-2.3c0.2,-0.2 0.4,-0.2 0.6,-0.1l2.3,1c0.2,0.2 0.5,0 0.7,-0.1l2.2,-2.8a0.6,0.6 0,0 1,1 0l2.4,3.4 0.1,0.4v3zM8.5,8a1.5,1.5 0,1 1,0 3,1.5 1.5,0 0,1 0,-3z"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
|
@ -3,25 +3,25 @@
|
|||
- 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/. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group>
|
||||
<clip-path android:pathData="M 18.8 2.8 C 19.8 1.8 21.1 3.3 20.2 4.2 L 3.4 21 L 2 19.6 L 18.8 2.8 Z"/>
|
||||
<clip-path android:pathData="M 18.8 2.8 C 19.8 1.8 21.1 3.3 20.2 4.2 L 3.4 21 L 2 19.6 L 18.8 2.8 Z" />
|
||||
<path
|
||||
android:name="strike_thru_path"
|
||||
android:pathData="M 20 1.6 L 21.4 3 L 5.2 19.2 C 4.2 20.2 2.8 18.8 3.8 17.8 L 20 1.6 Z"
|
||||
android:fillColor="@color/disabled_text"
|
||||
android:strokeWidth="1"/>
|
||||
android:name="strike_thru_path"
|
||||
android:fillColor="@color/disabled_text"
|
||||
android:pathData="M 20 1.6 L 21.4 3 L 5.2 19.2 C 4.2 20.2 2.8 18.8 3.8 17.8 L 20 1.6 Z"
|
||||
android:strokeWidth="1" />
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:name="strike_thru_mask"
|
||||
android:pathData="M 0 0 L 0 24 L 24 24 L 24 0 L 0 0 Z M 21 2 L 23 4 L 6 21 L 4 19 L 21 2 Z"/>
|
||||
android:name="strike_thru_mask"
|
||||
android:pathData="M 0 0 L 0 24 L 24 24 L 24 0 L 0 0 Z M 21 2 L 23 4 L 6 21 L 4 19 L 21 2 Z" />
|
||||
<path
|
||||
android:name="icon"
|
||||
android:fillColor="@color/disabled_text"
|
||||
android:pathData="M20 6c0-1-0.8-1.9-1.8-2L12 3 5.8 4C4.8 4 4 5 4 6l0.1 5c0.3 3.2 1 5 2.5 7a8.4 8.4 0 0 0 5.3 3h0.2c2.1-0.3 4-1.4 5.3-3 1.6-2 2.2-3.8 2.5-7l0.1-5zm-2.1 4.8a10 10 0 0 1-2 6c-1 1.1-2.4 2-3.9 2.3a6.5 6.5 0 0 1-3.9-2.4 9.9 9.9 0 0 1-2-5.9 67.3 67.3 0 0 1 0-4.9L12 5l5.9 1 0.1 0.2-0.1 4.7zM8 7.6v3c0.3 2.7 0.8 3.7 1.7 5 0.6 0.6 1.4 1.2 2.3 1.4V7l-4 0.6z" />
|
||||
android:name="icon"
|
||||
android:fillColor="@color/disabled_text"
|
||||
android:pathData="M20 6c0-1-0.8-1.9-1.8-2L12 3 5.8 4C4.8 4 4 5 4 6l0.1 5c0.3 3.2 1 5 2.5 7a8.4 8.4 0 0 0 5.3 3h0.2c2.1-0.3 4-1.4 5.3-3 1.6-2 2.2-3.8 2.5-7l0.1-5zm-2.1 4.8a10 10 0 0 1-2 6c-1 1.1-2.4 2-3.9 2.3a6.5 6.5 0 0 1-3.9-2.4 9.9 9.9 0 0 1-2-5.9 67.3 67.3 0 0 1 0-4.9L12 5l5.9 1 0.1 0.2-0.1 4.7zM8 7.6v3c0.3 2.7 0.8 3.7 1.7 5 0.6 0.6 1.4 1.2 2.3 1.4V7l-4 0.6z" />
|
||||
</group>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<rotate
|
||||
android:fromDegrees="45"
|
||||
android:pivotX="-40%"
|
||||
android:pivotY="87%"
|
||||
android:toDegrees="45">
|
||||
<shape android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="10dp"
|
||||
android:color="#0250BB" />
|
||||
<solid android:color="#0250BB" />
|
||||
</shape>
|
||||
</rotate>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. --><shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="225"
|
||||
android:endColor="#0250BB"
|
||||
android:startColor="#9059FF"
|
||||
android:type="linear" />
|
||||
<size
|
||||
android:width="256dp"
|
||||
android:height="152dp" />
|
||||
<corners
|
||||
android:bottomLeftRadius="8dp"
|
||||
android:bottomRightRadius="8dp"
|
||||
android:topLeftRadius="8dp"
|
||||
android:topRightRadius="8dp" />
|
||||
</shape>
|
|
@ -0,0 +1,259 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/panel_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?foundation">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/normal_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/url"
|
||||
style="@style/QuickSettingsText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="https://wikipedia.org" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.SwitchWithDescription
|
||||
android:id="@+id/tracking_protection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:text="@string/preference_enhanced_tracking_protection"
|
||||
app:layout_constraintTop_toBottomOf="@id/url"
|
||||
app:switchDescription="@string/etp_panel_on"
|
||||
app:switchIcon="@drawable/ic_tracking_protection"
|
||||
app:switchTitle="@string/preference_enhanced_tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/blocking_header"
|
||||
style="@style/QuickSettingsText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:text="@string/enhanced_tracking_protection_blocked"
|
||||
android:textColor="?attr/primaryText"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cross_site_tracking"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_cookies"
|
||||
android:text="@string/etp_cookies_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/blocking_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fingerprinters"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_fingerprinters"
|
||||
android:text="@string/etp_fingerprinters_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/cross_site_tracking" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cryptominers"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_cryptominers"
|
||||
android:text="@string/etp_cryptominers_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/fingerprinters" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/social_media_trackers"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_social_media_trackers"
|
||||
android:text="@string/etp_social_media_trackers_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/cryptominers" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tracking_content"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_tracking_content"
|
||||
android:text="@string/etp_tracking_content_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/social_media_trackers" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/not_blocking_header"
|
||||
style="@style/QuickSettingsText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:text="@string/enhanced_tracking_protection_allowed"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cross_site_tracking_loaded"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_cookies"
|
||||
android:text="@string/etp_cookies_title"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/not_blocking_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fingerprinters_loaded"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_fingerprinters"
|
||||
android:text="@string/etp_fingerprinters_title"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/cross_site_tracking_loaded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cryptominers_loaded"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_cryptominers"
|
||||
android:text="@string/etp_cryptominers_title"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/fingerprinters_loaded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/social_media_trackers_loaded"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_social_media_trackers"
|
||||
android:text="@string/etp_social_media_trackers_title"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/cryptominers_loaded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tracking_content_loaded"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_tracking_content"
|
||||
android:text="@string/etp_tracking_content_title"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/social_media_trackers_loaded" />
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_content_loaded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/protection_settings"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:drawableStart="@drawable/ic_settings"
|
||||
android:paddingEnd="24dp"
|
||||
android:text="@string/etp_settings"
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/details_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/details_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:src="@drawable/mozac_ic_back"
|
||||
android:tint="?attr/primaryText"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/category_description"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/category_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="52dp"
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_marginEnd="19dp"
|
||||
android:textColor="?attr/primaryText"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="52dp"
|
||||
android:layout_marginEnd="19dp"
|
||||
android:textColor="?secondaryText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/category_title"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider_details"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintTop_toBottomOf="@id/category_description" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/details_blocking_header"
|
||||
style="@style/QuickSettingsText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:layout_marginStart="52dp"
|
||||
android:layout_marginEnd="26dp"
|
||||
android:paddingStart="0dp"
|
||||
android:text="@string/enhanced_tracking_protection_blocked"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider_details" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/blocking_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/details_blocking_header"
|
||||
app:layout_constraintTop_toBottomOf="@id/details_blocking_header">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/blocking_text_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="52dp"
|
||||
android:layout_marginEnd="26dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -7,6 +7,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
android:text="@string/preferences_tracking_protection_exceptions_description"
|
||||
android:text="@string/enhanced_tracking_protection_exceptions"
|
||||
android:textColor="?primaryText"
|
||||
android:textSize="16sp" />
|
||||
|
|
|
@ -22,22 +22,22 @@
|
|||
style="@style/QuickSettingsText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="https://wikipedia.org"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
tools:text="https://wikipedia.org" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/security_info"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/url"
|
||||
tools:drawableStart="@drawable/mozac_ic_lock"
|
||||
tools:drawableTint="@color/photonGreen50"
|
||||
tools:text="Secure connection"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
tools:text="Secure connection" />
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider_security"
|
||||
|
@ -49,62 +49,71 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/security_info" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/tracking_protection"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/tracking_protection_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
tools:drawableStart="@drawable/ic_tracking_protection"
|
||||
android:paddingEnd="24dp"
|
||||
android:text="@string/preferences_tracking_protection"
|
||||
app:layout_constraintBottom_toTopOf="@id/tracking_protection_action"
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider_security" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tracking_protection_action"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:gravity="top"
|
||||
android:paddingStart="48dp"
|
||||
android:text="@string/preferences_tracking_protection_turned_off_globally"
|
||||
android:textColor="?accentBright"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/report_site_issue_action"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_site_issue_action"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:gravity="top"
|
||||
android:paddingStart="48dp"
|
||||
android:text="@string/browser_menu_report_issue"
|
||||
android:textColor="?accentUsedOnDarkBackground"
|
||||
app:layout_constraintBottom_toTopOf="@id/line_divider"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_action" />
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?neutralFaded"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/camera_icon"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider_security">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/tracking_protection"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:paddingEnd="24dp"
|
||||
android:text="@string/preferences_tracking_protection"
|
||||
app:layout_constraintBottom_toTopOf="@id/tracking_protection_action"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:drawableStart="@drawable/ic_tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tracking_protection_action"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:gravity="top"
|
||||
android:paddingStart="48dp"
|
||||
android:text="@string/preferences_tracking_protection_turned_off_globally"
|
||||
android:textColor="?accentBright"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/report_site_issue_action"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_site_issue_action"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:gravity="top"
|
||||
android:paddingStart="48dp"
|
||||
android:text="@string/browser_menu_report_issue"
|
||||
android:textColor="?accentUsedOnDarkBackground"
|
||||
app:layout_constraintBottom_toTopOf="@id/line_divider"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_action" />
|
||||
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/camera_icon"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:text="@string/preference_phone_feature_camera"
|
||||
android:drawableStart="@drawable/ic_camera"
|
||||
android:text="@string/preference_phone_feature_camera"
|
||||
app:layout_constraintEnd_toStartOf="@+id/camera_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider"
|
||||
app:layout_constraintEnd_toStartOf="@+id/camera_action_label"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_view" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/camera_action_label"
|
||||
|
@ -112,7 +121,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_view"
|
||||
tools:text="Allowed" />
|
||||
|
||||
<TextView
|
||||
|
@ -120,11 +129,11 @@
|
|||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:text="@string/preference_phone_feature_microphone"
|
||||
android:drawableStart="@drawable/ic_microphone"
|
||||
android:text="@string/preference_phone_feature_microphone"
|
||||
app:layout_constraintEnd_toStartOf="@+id/microphone_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/camera_icon"
|
||||
app:layout_constraintEnd_toStartOf="@+id/microphone_action_label"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/camera_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/microphone_action_label"
|
||||
|
@ -140,11 +149,11 @@
|
|||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:text="@string/preference_phone_feature_notification"
|
||||
android:drawableStart="@drawable/ic_notifications"
|
||||
android:text="@string/preference_phone_feature_notification"
|
||||
app:layout_constraintEnd_toStartOf="@+id/notification_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/microphone_icon"
|
||||
app:layout_constraintEnd_toStartOf="@+id/notification_action_label" />
|
||||
app:layout_constraintTop_toBottomOf="@id/microphone_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_action_label"
|
||||
|
@ -160,11 +169,11 @@
|
|||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
android:text="@string/preference_phone_feature_location"
|
||||
android:drawableStart="@drawable/ic_location"
|
||||
android:text="@string/preference_phone_feature_location"
|
||||
app:layout_constraintEnd_toStartOf="@+id/location_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notification_icon"
|
||||
app:layout_constraintEnd_toStartOf="@+id/location_action_label"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/notification_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/location_action_label"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/fragment_tp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"/>
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/details_blocking_header"
|
||||
style="@style/QuickSettingsText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/tracking_protection_item_height"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingStart="0dp"
|
||||
android:text="@string/enhanced_tracking_protection_blocked"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.TrackingProtectionCategoryItem
|
||||
android:id="@+id/category_social_media"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:categoryItemDescription="@string/etp_social_media_trackers_description"
|
||||
app:categoryItemIcon="@drawable/ic_social_media_trackers"
|
||||
app:categoryItemTitle="@string/etp_social_media_trackers_title" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.TrackingProtectionCategoryItem
|
||||
android:id="@+id/category_cookies"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:categoryItemDescription="@string/etp_cookies_description"
|
||||
app:categoryItemIcon="@drawable/ic_cookies"
|
||||
app:categoryItemTitle="@string/etp_cookies_title" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.TrackingProtectionCategoryItem
|
||||
android:id="@+id/category_cryptominers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:categoryItemDescription="@string/etp_cryptominers_description"
|
||||
app:categoryItemIcon="@drawable/ic_cryptominers"
|
||||
app:categoryItemTitle="@string/etp_cryptominers_title" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.TrackingProtectionCategoryItem
|
||||
android:id="@+id/category_fingerprinters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:categoryItemDescription="@string/etp_fingerprinters_description"
|
||||
app:categoryItemIcon="@drawable/ic_fingerprinters"
|
||||
app:categoryItemTitle="@string/etp_fingerprinters_title" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.TrackingProtectionCategoryItem
|
||||
android:id="@+id/category_tracking_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:categoryItemDescription="@string/etp_tracking_content_description"
|
||||
app:categoryItemIcon="@drawable/ic_tracking_content"
|
||||
app:categoryItemTitle="@string/etp_tracking_content_title" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
|
@ -6,7 +6,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/relativeLayout"
|
||||
android:id="@+id/constraintLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/constraintLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||
android:paddingBottom="@dimen/radio_button_preference_vertical">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginStart="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:button="@null"
|
||||
android:clickable="false"
|
||||
android:drawablePadding="6dp"
|
||||
android:focusable="false"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:drawableStart="?android:attr/listChoiceIndicatorSingle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:gravity="center|start"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
app:layout_constraintBottom_toBottomOf="@id/radio_button"
|
||||
app:layout_constraintEnd_toStartOf="@+id/vertical_divider"
|
||||
app:layout_constraintStart_toEndOf="@+id/radio_button"
|
||||
app:layout_constraintTop_toTopOf="@id/radio_button"
|
||||
tools:text="Use recommended settings" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/widget_summary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintEnd_toStartOf="@+id/vertical_divider"
|
||||
app:layout_constraintStart_toStartOf="@+id/title"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vertical_divider"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/info_button"
|
||||
app:layout_constraintStart_toEndOf="@+id/title"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/info_button"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:src="@drawable/ic_info"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/vertical_divider"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/switchItemTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="48dp"
|
||||
android:layout_marginEnd="64dp"
|
||||
android:clickable="false"
|
||||
android:textAppearance="@style/ListItemTextStyle"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/switchItemDescription"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/switchItemDescription"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false"
|
||||
android:textColor="?attr/secondaryText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/switchItemTitle"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="@id/switchItemTitle"
|
||||
app:layout_constraintTop_toBottomOf="@+id/switchItemTitle"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switch_widget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/library_item_icon_margin_horizontal"
|
||||
android:drawableStart="@drawable/ic_tracking_protection"
|
||||
app:layout_constraintBottom_toBottomOf="@id/switchItemDescription"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/switchItemTitle" />
|
||||
</merge>
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/switchIcon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/library_item_icon_margin_vertical"
|
||||
android:layout_marginEnd="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginBottom="@dimen/library_item_icon_margin_vertical"
|
||||
android:background="@drawable/ic_cryptominers"
|
||||
android:clickable="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/switchItemTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="@dimen/library_item_icon_margin_horizontal"
|
||||
android:clickable="false"
|
||||
android:textAppearance="@style/ListItemTextStyle"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/switchItemDescription"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@id/switchIcon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/switchItemDescription"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/library_item_icon_margin_horizontal"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:clickable="false"
|
||||
android:textColor="?attr/secondaryText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@id/switchIcon"
|
||||
app:layout_constraintTop_toBottomOf="@+id/switchItemTitle"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
</merge>
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_etp_artwork"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:ellipsize="none"
|
||||
android:letterSpacing="0.05"
|
||||
android:scrollHorizontally="false"
|
||||
android:singleLine="false"
|
||||
android:text="@string/preference_enhanced_tracking_protection_explanation_title"
|
||||
android:textAppearance="@style/Header16TextStyle"
|
||||
android:textColor="@color/primary_text_dark_theme"
|
||||
app:layout_constraintBottom_toTopOf="@android:id/summary"
|
||||
app:layout_constraintEnd_toStartOf="@id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="none"
|
||||
android:scrollHorizontally="false"
|
||||
android:text="@string/preference_enhanced_tracking_protection_explanation"
|
||||
android:textColor="@color/primary_text_dark_theme"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/guideline"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="@android:id/title"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/learn_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:ellipsize="none"
|
||||
android:text="@string/preference_enhanced_tracking_protection_explanation_learn_more"
|
||||
android:textColor="@color/primary_text_dark_theme"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/guideline"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="@android:id/title"
|
||||
app:layout_constraintTop_toBottomOf="@android:id/summary" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_arrowhead_right"
|
||||
android:tint="@color/primary_text_dark_theme"
|
||||
app:layout_constraintBottom_toBottomOf="@id/learn_more"
|
||||
app:layout_constraintStart_toEndOf="@id/learn_more"
|
||||
app:layout_constraintTop_toTopOf="@id/learn_more" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="210dp" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/onboarding_popup_background"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/onboarding_message"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:text="@string/etp_onboarding_message"
|
||||
android:textColor="@color/primary_text_dark_theme"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/close_onboarding"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close_onboarding"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:src="@drawable/ic_close"
|
||||
android:tint="@color/primary_text_dark_theme"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:rotation="180"
|
||||
android:src="@drawable/ic_triangle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/message" />
|
||||
</LinearLayout>
|
|
@ -100,8 +100,8 @@
|
|||
app:nullable="true" />
|
||||
<argument
|
||||
android:name="showShortcutEnginePicker"
|
||||
app:argType="boolean"
|
||||
android:defaultValue="false" />
|
||||
android:defaultValue="false"
|
||||
app:argType="boolean" />
|
||||
<action
|
||||
android:id="@+id/action_searchFragment_to_searchEngineFragment"
|
||||
app:destination="@id/searchEngineFragment"
|
||||
|
@ -185,22 +185,28 @@
|
|||
<action
|
||||
android:id="@+id/action_browserFragment_to_quickSettingsSheetDialogFragment"
|
||||
app:destination="@id/quickSettingsSheetDialogFragment" />
|
||||
<action
|
||||
android:id="@+id/action_browserFragment_to_trackingProtectionPanelDialogFragment"
|
||||
app:destination="@id/trackingProtectionPanelDialogFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/externalAppBrowserFragment"
|
||||
android:name="org.mozilla.fenix.customtabs.ExternalAppBrowserFragment"
|
||||
tools:layout="@layout/fragment_browser">
|
||||
android:id="@+id/externalAppBrowserFragment"
|
||||
android:name="org.mozilla.fenix.customtabs.ExternalAppBrowserFragment"
|
||||
tools:layout="@layout/fragment_browser">
|
||||
<argument
|
||||
android:name="activeSessionId"
|
||||
app:argType="string"
|
||||
app:nullable="true" />
|
||||
android:name="activeSessionId"
|
||||
app:argType="string"
|
||||
app:nullable="true" />
|
||||
<action
|
||||
android:id="@+id/action_externalAppBrowserFragment_to_shareFragment"
|
||||
app:destination="@id/shareFragment" />
|
||||
android:id="@+id/action_externalAppBrowserFragment_to_shareFragment"
|
||||
app:destination="@id/shareFragment" />
|
||||
<action
|
||||
android:id="@+id/action_externalAppBrowserFragment_to_quickSettingsSheetDialogFragment"
|
||||
app:destination="@id/quickSettingsSheetDialogFragment" />
|
||||
android:id="@+id/action_externalAppBrowserFragment_to_quickSettingsSheetDialogFragment"
|
||||
app:destination="@id/quickSettingsSheetDialogFragment" />
|
||||
<action
|
||||
android:id="@+id/action_externalAppBrowserFragment_to_trackingProtectionPanelDialogFragment"
|
||||
app:destination="@id/trackingProtectionPanelDialogFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -396,13 +402,12 @@
|
|||
<fragment
|
||||
android:id="@+id/pairFragment"
|
||||
android:name="org.mozilla.fenix.settings.PairFragment"
|
||||
android:label="@string/preferences_sync">
|
||||
</fragment>
|
||||
android:label="@string/preferences_sync"></fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/aboutFragment"
|
||||
android:name="org.mozilla.fenix.settings.AboutFragment"
|
||||
android:label="AboutFragment" >
|
||||
android:label="AboutFragment">
|
||||
<action
|
||||
android:id="@+id/action_aboutFragment_to_browserFragment"
|
||||
app:destination="@id/browserFragment" />
|
||||
|
@ -414,7 +419,7 @@
|
|||
<action
|
||||
android:id="@+id/action_crashReporterFragment_to_homeFragment"
|
||||
app:destination="@id/homeFragment"
|
||||
app:popUpTo="@id/nav_graph"/>
|
||||
app:popUpTo="@id/nav_graph" />
|
||||
<argument
|
||||
android:name="crashIntent"
|
||||
app:argType="android.content.Intent" />
|
||||
|
@ -430,6 +435,12 @@
|
|||
<action
|
||||
android:id="@+id/action_trackingProtectionFragment_to_exceptionsFragment"
|
||||
app:destination="@id/exceptionsFragment" />
|
||||
<action
|
||||
android:id="@+id/action_trackingProtectionFragment_to_trackingProtectionBlockingFragment"
|
||||
app:destination="@id/trackingProtectionBlockingFragment" />
|
||||
<action
|
||||
android:id="@+id/action_trackingProtectionFragment_to_browserFragment"
|
||||
app:destination="@id/browserFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/deleteBrowsingDataFragment"
|
||||
|
@ -515,6 +526,36 @@
|
|||
<dialog
|
||||
android:id="@+id/signOutFragment"
|
||||
android:name="org.mozilla.fenix.settings.SignOutFragment" />
|
||||
<action android:id="@+id/action_global_shareFragment"
|
||||
app:destination="@id/shareFragment"/>
|
||||
<action
|
||||
android:id="@+id/action_global_shareFragment"
|
||||
app:destination="@id/shareFragment" />
|
||||
<dialog
|
||||
android:id="@+id/trackingProtectionPanelDialogFragment"
|
||||
android:name="org.mozilla.fenix.trackingprotection.TrackingProtectionPanelDialogFragment"
|
||||
android:label="TrackingProtectionPanelDialogFragment">
|
||||
<argument
|
||||
android:name="sessionId"
|
||||
app:argType="string" />
|
||||
<argument
|
||||
android:name="url"
|
||||
app:argType="string" />
|
||||
<argument
|
||||
android:name="trackingProtectionEnabled"
|
||||
app:argType="boolean" />
|
||||
<argument
|
||||
android:name="gravity"
|
||||
android:defaultValue="80"
|
||||
app:argType="integer" />
|
||||
<action
|
||||
android:id="@+id/action_trackingProtectionPanelDialogFragment_to_trackingProtectionFragment"
|
||||
app:destination="@id/trackingProtectionFragment" />
|
||||
</dialog>
|
||||
<fragment
|
||||
android:id="@+id/trackingProtectionBlockingFragment"
|
||||
android:name="org.mozilla.fenix.trackingprotection.TrackingProtectionBlockingFragment"
|
||||
android:label="TrackingProtectionBlockingFragment">
|
||||
<argument
|
||||
android:name="strictMode"
|
||||
app:argType="boolean" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -33,12 +33,25 @@
|
|||
<attr name="toolbarStartGradient" format="reference"/>
|
||||
<attr name="toolbarCenterGradient" format="reference"/>
|
||||
<attr name="toolbarEndGradient" format="reference"/>
|
||||
<attr name="shieldLottieFile" format="reference" />
|
||||
|
||||
<declare-styleable name="LibraryListItem">
|
||||
<attr name="listItemTitle" format="reference" />
|
||||
<attr name="listItemIcon" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="TrackingProtectionCategory">
|
||||
<attr name="categoryItemTitle" format="reference" />
|
||||
<attr name="categoryItemDescription" format="reference" />
|
||||
<attr name="categoryItemIcon" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SwitchWithDescription">
|
||||
<attr name="switchTitle" format="reference" />
|
||||
<attr name="switchDescription" format="reference" />
|
||||
<attr name="switchIcon" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="DeleteBrowsingDataItem">
|
||||
<attr name="deleteBrowsingDataItemTitle" format="reference" />
|
||||
<attr name="deleteBrowsingDataItemSubtitle" format="reference" />
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
<!--Quick Settings-->
|
||||
<dimen name="quicksettings_item_height">46dp</dimen>
|
||||
<dimen name="tracking_protection_item_height">48dp</dimen>
|
||||
|
||||
<dimen name="design_quick_action_sheet_peek_height_min">64dp</dimen>
|
||||
|
||||
|
@ -51,4 +52,7 @@
|
|||
<dimen name="sign_in_button_padding">10dp</dimen>
|
||||
<dimen name="sign_in_button_margin_top">32dp</dimen>
|
||||
<dimen name="sign_in_button_margin">16dp</dimen>
|
||||
|
||||
<!-- ETP Onboarding Popup -->
|
||||
<dimen name="etp_onboarding_popup_width">256dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -77,10 +77,13 @@
|
|||
<string name="pref_key_follow_device_theme" translatable="false">pref_key_follow_device_theme</string>
|
||||
|
||||
<!-- Tracking Protection Settings -->
|
||||
<string name="pref_key_etp_learn_more" translatable="false">pref_key_etp_learn_more</string>
|
||||
<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_onboarding" translatable="false">pref_key_tracking_protection_onboarding</string>
|
||||
<!-- Quick Action Sheet -->
|
||||
<string name="pref_key_bounce_quick_action" translatable="false">pref_key_bounce_quick_action</string>
|
||||
<string name="pref_key_reader_mode_notification" translatable="false">pref_key_reader_mode_notification</string>
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
<item name="homeBackground">@color/foundation_normal_theme</item>
|
||||
<item name="privateBrowsingButtonBackground">@android:color/transparent</item>
|
||||
<item name="privateBrowsingButtonAccent">@color/primary_text_normal_theme</item>
|
||||
<item name="shieldLottieFile">@raw/shield_json</item>
|
||||
</style>
|
||||
|
||||
<style name="NormalTheme" parent="NormalThemeBase" />
|
||||
|
@ -134,6 +135,7 @@
|
|||
<item name="homeBackground">@drawable/private_home_background_gradient</item>
|
||||
<item name="privateBrowsingButtonBackground">@color/primary_text_private_theme</item>
|
||||
<item name="privateBrowsingButtonAccent">@color/above_private_theme</item>
|
||||
<item name="shieldLottieFile">@raw/shield_json_dark</item>
|
||||
|
||||
</style>
|
||||
|
||||
|
@ -271,6 +273,7 @@
|
|||
<item name="android:textColor">@color/state_list_text_color</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:paddingStart">16dp</item>
|
||||
<item name="android:paddingEnd">16dp</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:layout_alignParentStart">true</item>
|
||||
</style>
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<androidx.preference.Preference
|
||||
android:icon="@drawable/ic_tracking_protection_enabled"
|
||||
android:key="@string/pref_key_tracking_protection_settings"
|
||||
android:title="@string/preferences_tracking_protection" />
|
||||
android:title="@string/preference_enhanced_tracking_protection" />
|
||||
<androidx.preference.Preference
|
||||
android:icon="@drawable/ic_permission"
|
||||
android:key="@string/pref_key_site_permissions"
|
||||
|
|
|
@ -2,15 +2,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/. -->
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<androidx.preference.Preference
|
||||
app:allowDividerBelow="false"
|
||||
android:key="@string/pref_key_etp_learn_more"
|
||||
android:layout="@layout/tracking_protection_learn_more_preference"
|
||||
android:summary="@string/preference_enhanced_tracking_protection_explanation"
|
||||
android:title="@string/preference_enhanced_tracking_protection_explanation_title" />
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:icon="@drawable/ic_tracking_protection_enabled"
|
||||
android:key="@string/pref_key_tracking_protection"
|
||||
android:summary="@string/preferences_tracking_protection_description"
|
||||
android:title="@string/preferences_tracking_protection" />
|
||||
android:title="@string/preference_enhanced_tracking_protection" />
|
||||
<org.mozilla.fenix.settings.RadioButtonInfoPreference
|
||||
android:dependency="@string/pref_key_tracking_protection"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/pref_key_tracking_protection_standard"
|
||||
android:summary="@string/preference_enhanced_tracking_protection_standard_description"
|
||||
android:title="@string/preference_enhanced_tracking_protection_standard" />
|
||||
<org.mozilla.fenix.settings.RadioButtonInfoPreference
|
||||
android:dependency="@string/pref_key_tracking_protection"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/pref_key_tracking_protection_strict"
|
||||
android:summary="@string/preference_enhanced_tracking_protection_strict_description"
|
||||
android:title="@string/preference_enhanced_tracking_protection_strict" />
|
||||
<Preference
|
||||
android:icon="@drawable/ic_internet"
|
||||
app:allowDividerAbove="true"
|
||||
android:icon="@drawable/ic_info"
|
||||
android:key="@string/pref_key_tracking_protection_exceptions"
|
||||
android:title="@string/preferences_tracking_protection_exceptions" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* 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 io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
|
||||
class TrackingProtectionPanelInteractorTest {
|
||||
|
||||
@Test
|
||||
fun openDetails() {
|
||||
val store: TrackingProtectionStore = mockk(relaxed = true)
|
||||
val interactor =
|
||||
TrackingProtectionPanelInteractor(store, mockk(), mockk())
|
||||
interactor.openDetails(TrackingProtectionCategory.FINGERPRINTERS, true)
|
||||
verify {
|
||||
store.dispatch(
|
||||
TrackingProtectionAction.EnterDetailsMode(
|
||||
TrackingProtectionCategory.FINGERPRINTERS,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun selectTrackingProtectionSettings() {
|
||||
var openSettings = false
|
||||
val interactor = TrackingProtectionPanelInteractor(
|
||||
mockk(),
|
||||
mockk(),
|
||||
{ openSettings = true }
|
||||
)
|
||||
interactor.selectTrackingProtectionSettings()
|
||||
assertEquals(true, openSettings)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun trackingProtectionToggled() {
|
||||
var trackingProtectionNewValue: Boolean? = null
|
||||
val interactor = TrackingProtectionPanelInteractor(
|
||||
mockk(),
|
||||
{ trackingProtectionNewValue = it },
|
||||
mockk()
|
||||
)
|
||||
interactor.trackingProtectionToggled(true)
|
||||
assertEquals(true, trackingProtectionNewValue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onBackPressed() {
|
||||
val store: TrackingProtectionStore = mockk(relaxed = true)
|
||||
val interactor =
|
||||
TrackingProtectionPanelInteractor(store, mockk(), mockk())
|
||||
interactor.onBackPressed()
|
||||
verify { store.dispatch(TrackingProtectionAction.ExitDetailsMode) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/* 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 org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotSame
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import mozilla.components.concept.engine.content.blocking.Tracker
|
||||
import org.junit.Test
|
||||
|
||||
class TrackingProtectionStoreTest {
|
||||
@Test
|
||||
fun enterDetailsMode() = runBlocking {
|
||||
val initialState = defaultState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
|
||||
store.dispatch(
|
||||
TrackingProtectionAction.EnterDetailsMode(
|
||||
TrackingProtectionCategory.FINGERPRINTERS,
|
||||
true
|
||||
)
|
||||
)
|
||||
.join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
store.state.mode,
|
||||
TrackingProtectionState.Mode.Details(TrackingProtectionCategory.FINGERPRINTERS, true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun exitDetailsMode() = runBlocking {
|
||||
val initialState = detailsState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
|
||||
store.dispatch(TrackingProtectionAction.ExitDetailsMode).join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
store.state.mode,
|
||||
TrackingProtectionState.Mode.Normal
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun trackerBlockingChanged() = runBlocking {
|
||||
val initialState = defaultState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
|
||||
store.dispatch(TrackingProtectionAction.TrackerBlockingChanged(false)).join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
store.state.mode,
|
||||
TrackingProtectionState.Mode.Normal
|
||||
)
|
||||
assertEquals(
|
||||
false,
|
||||
store.state.isTrackingProtectionEnabled
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun trackerListChanged() = runBlocking {
|
||||
val initialState = defaultState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
val tracker = Tracker("url", listOf())
|
||||
|
||||
store.dispatch(TrackingProtectionAction.TrackerListChange(listOf(tracker))).join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
listOf(tracker),
|
||||
store.state.listTrackers
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun trackerLoadedListChanged() = runBlocking {
|
||||
val initialState = defaultState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
val tracker = Tracker("url", listOf())
|
||||
|
||||
store.dispatch(TrackingProtectionAction.TrackerLoadedListChange(listOf(tracker))).join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
listOf(tracker),
|
||||
store.state.listTrackersLoaded
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun urlChanged() = runBlocking {
|
||||
val initialState = defaultState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
|
||||
store.dispatch(TrackingProtectionAction.UrlChange("newURL")).join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
"newURL",
|
||||
store.state.url
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onChange() = runBlocking {
|
||||
val initialState = defaultState()
|
||||
val store = TrackingProtectionStore(initialState)
|
||||
val tracker = Tracker("url", listOf())
|
||||
|
||||
store.dispatch(
|
||||
TrackingProtectionAction.Change(
|
||||
"newURL",
|
||||
false,
|
||||
listOf(tracker),
|
||||
listOf(),
|
||||
TrackingProtectionState.Mode.Details(
|
||||
TrackingProtectionCategory.FINGERPRINTERS,
|
||||
true
|
||||
)
|
||||
)
|
||||
).join()
|
||||
assertNotSame(initialState, store.state)
|
||||
assertEquals(
|
||||
"newURL",
|
||||
store.state.url
|
||||
)
|
||||
assertEquals(
|
||||
false,
|
||||
store.state.isTrackingProtectionEnabled
|
||||
)
|
||||
assertEquals(
|
||||
listOf<Tracker>(),
|
||||
store.state.listTrackersLoaded
|
||||
)
|
||||
assertEquals(
|
||||
listOf(tracker),
|
||||
store.state.listTrackers
|
||||
)
|
||||
assertEquals(
|
||||
TrackingProtectionState.Mode.Details(TrackingProtectionCategory.FINGERPRINTERS, true),
|
||||
store.state.mode
|
||||
)
|
||||
}
|
||||
|
||||
private fun defaultState(): TrackingProtectionState = TrackingProtectionState(
|
||||
url = "www.mozilla.org",
|
||||
isTrackingProtectionEnabled = true,
|
||||
listTrackers = listOf(),
|
||||
listTrackersLoaded = listOf(),
|
||||
mode = TrackingProtectionState.Mode.Normal
|
||||
)
|
||||
|
||||
private fun detailsState(): TrackingProtectionState = TrackingProtectionState(
|
||||
url = "www.mozilla.org",
|
||||
isTrackingProtectionEnabled = true,
|
||||
listTrackers = listOf(),
|
||||
listTrackersLoaded = listOf(),
|
||||
mode = TrackingProtectionState.Mode.Details(TrackingProtectionCategory.CRYPTOMINERS, true)
|
||||
)
|
||||
}
|
|
@ -64,6 +64,9 @@ object Versions {
|
|||
const val robolectric = "4.2"
|
||||
|
||||
const val google_ads_id_version = "16.0.0"
|
||||
|
||||
const val airbnb_lottie = "3.0.7"
|
||||
|
||||
const val androidx_fragment_testing_version = "1.2.0-alpha02"
|
||||
}
|
||||
|
||||
|
@ -217,4 +220,6 @@ object Deps {
|
|||
|
||||
const val google_ads_id = "com.google.android.gms:play-services-ads-identifier:${Versions.google_ads_id_version}"
|
||||
const val androidx_fragment_testing = "androidx.fragment:fragment-testing:${Versions.androidx_fragment_testing_version}"
|
||||
|
||||
const val lottie = "com.airbnb.android:lottie:${Versions.airbnb_lottie}"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue