Extract TP onboarding popup (#6700)
This commit is contained in:
parent
0d6ea08de7
commit
bd475d54e5
|
@ -5,17 +5,12 @@
|
|||
package org.mozilla.fenix.browser
|
||||
|
||||
import android.content.Context
|
||||
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.view.WindowManager
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.RadioButton
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
|
@ -24,7 +19,6 @@ import androidx.transition.TransitionInflater
|
|||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.feature.contextmenu.ContextMenuCandidate
|
||||
|
@ -35,21 +29,19 @@ import mozilla.components.feature.tabs.WindowFeature
|
|||
import mozilla.components.lib.state.ext.consumeFrom
|
||||
import mozilla.components.support.base.feature.BackHandler
|
||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||
import org.jetbrains.anko.dimen
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.components.FenixSnackbar
|
||||
import org.mozilla.fenix.components.TabCollectionStorage
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.getDimenInDip
|
||||
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
|
||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionOverlay
|
||||
|
||||
/**
|
||||
* Fragment used for browsing the web within the main app.
|
||||
|
@ -127,17 +119,16 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
override fun onStart() {
|
||||
super.onStart()
|
||||
subscribeToTabCollections()
|
||||
getSessionById()?.register(toolbarSessionObserver, this, autoPause = true)
|
||||
}
|
||||
|
||||
private val toolbarSessionObserver = object : Session.Observer {
|
||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
||||
if (!loading &&
|
||||
shouldShowTrackingProtectionOnboarding(session)
|
||||
) {
|
||||
showTrackingProtectionOnboarding()
|
||||
}
|
||||
}
|
||||
val toolbarSessionObserver = TrackingProtectionOverlay(
|
||||
context = requireContext(),
|
||||
settings = requireContext().settings(),
|
||||
toolbar = browserToolbarView.view,
|
||||
trackingProtectionIcon = browserToolbarView
|
||||
.view
|
||||
.findViewById<AppCompatImageView>(R.id.mozac_browser_toolbar_tracking_protection_indicator)
|
||||
)
|
||||
getSessionById()?.register(toolbarSessionObserver, this, autoPause = true)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -254,54 +245,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private fun showTrackingProtectionOnboarding() {
|
||||
context?.let {
|
||||
val layout = LayoutInflater.from(it)
|
||||
.inflate(R.layout.tracking_protection_onboarding_popup, null)
|
||||
layout.onboarding_message.text =
|
||||
it.getString(R.string.etp_onboarding_message_2, getString(R.string.app_name))
|
||||
|
||||
val trackingOnboarding = PopupWindow(
|
||||
layout,
|
||||
it.dimen(R.dimen.tp_onboarding_width),
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
isOutsideTouchable = true
|
||||
isFocusable = true
|
||||
elevation = view!!.resources.getDimension(R.dimen.mozac_browser_menu_elevation)
|
||||
animationStyle = R.style.Mozac_Browser_Menu_Animation_OverflowMenuBottom
|
||||
}
|
||||
|
||||
val closeButton = layout.findViewById<ImageView>(R.id.close_onboarding)
|
||||
closeButton.increaseTapArea(BUTTON_INCREASE_DPS)
|
||||
closeButton.setOnClickListener {
|
||||
trackingOnboarding.dismiss()
|
||||
}
|
||||
|
||||
val tpIcon =
|
||||
browserToolbarView
|
||||
.view
|
||||
.findViewById<AppCompatImageView>(R.id.mozac_browser_toolbar_tracking_protection_indicator)
|
||||
|
||||
// Measure layout view
|
||||
val spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
|
||||
layout.measure(spec, spec)
|
||||
|
||||
val containerHeight = layout.measuredHeight
|
||||
val triangleHeight = it.getDimenInDip(R.dimen.tp_onboarding_triangle_height).toInt()
|
||||
|
||||
val xOffset = it.dimen(R.dimen.tp_onboarding_x_offset)
|
||||
|
||||
// Positioning the popup above the tp anchor.
|
||||
val yOffset =
|
||||
-containerHeight - (browserToolbarView.view.height / THREE * 2) + triangleHeight
|
||||
|
||||
trackingOnboarding.showAsDropDown(tpIcon, xOffset, yOffset)
|
||||
it.settings().incrementTrackingProtectionOnboardingCount()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContextMenuCandidates(
|
||||
context: Context,
|
||||
view: View
|
||||
|
@ -316,10 +259,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
)
|
||||
)
|
||||
|
||||
private fun shouldShowTrackingProtectionOnboarding(session: Session) =
|
||||
context?.settings()?.shouldShowTrackingProtectionOnboarding ?: false &&
|
||||
session.trackerBlockingEnabled && session.trackersBlocked.isNotEmpty()
|
||||
|
||||
companion object {
|
||||
private const val THREE = 3
|
||||
private const val BUTTON_INCREASE_DPS = 12
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/* 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.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.MeasureSpec
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import android.widget.PopupWindow
|
||||
import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.*
|
||||
import mozilla.components.browser.session.Session
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.getDimenInDip
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
/**
|
||||
* Displays an overlay above the tracking protection button in the browser toolbar
|
||||
* to onboard the user about tracking protection.
|
||||
*/
|
||||
class TrackingProtectionOverlay(
|
||||
private val context: Context,
|
||||
private val settings: Settings,
|
||||
private val toolbar: View,
|
||||
private val trackingProtectionIcon: View
|
||||
) : Session.Observer {
|
||||
|
||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
||||
if (!loading && shouldShowTrackingProtectionOnboarding(session)) {
|
||||
showTrackingProtectionOnboarding()
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldShowTrackingProtectionOnboarding(session: Session) =
|
||||
settings.shouldShowTrackingProtectionOnboarding &&
|
||||
session.trackerBlockingEnabled &&
|
||||
session.trackersBlocked.isNotEmpty()
|
||||
|
||||
@Suppress("MagicNumber", "InflateParams")
|
||||
private fun showTrackingProtectionOnboarding() {
|
||||
val layout = LayoutInflater.from(context)
|
||||
.inflate(R.layout.tracking_protection_onboarding_popup, null)
|
||||
layout.onboarding_message.text =
|
||||
context.getString(R.string.etp_onboarding_message_2, context.getString(R.string.app_name))
|
||||
|
||||
val trackingOnboarding = PopupWindow(
|
||||
layout,
|
||||
context.resources.getDimensionPixelSize(R.dimen.tp_onboarding_width),
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
isOutsideTouchable = true
|
||||
isFocusable = true
|
||||
elevation = context.resources.getDimension(R.dimen.mozac_browser_menu_elevation)
|
||||
animationStyle = R.style.Mozac_Browser_Menu_Animation_OverflowMenuBottom
|
||||
}
|
||||
|
||||
val closeButton = layout.findViewById<ImageView>(R.id.close_onboarding)
|
||||
closeButton.increaseTapArea(BUTTON_INCREASE_DPS)
|
||||
closeButton.setOnClickListener {
|
||||
trackingOnboarding.dismiss()
|
||||
}
|
||||
|
||||
// Measure layout view
|
||||
val spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
|
||||
layout.measure(spec, spec)
|
||||
|
||||
val containerHeight = layout.measuredHeight
|
||||
val triangleHeight = context.getDimenInDip(R.dimen.tp_onboarding_triangle_height).toInt()
|
||||
|
||||
val xOffset = context.resources.getDimensionPixelSize(R.dimen.tp_onboarding_x_offset)
|
||||
|
||||
// Positioning the popup above the tp anchor.
|
||||
val yOffset = -containerHeight - (toolbar.height / 3 * 2) + triangleHeight
|
||||
|
||||
trackingOnboarding.showAsDropDown(trackingProtectionIcon, xOffset, yOffset)
|
||||
settings.incrementTrackingProtectionOnboardingCount()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val BUTTON_INCREASE_DPS = 12
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* 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.view.View
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.TestApplication
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = TestApplication::class)
|
||||
class TrackingProtectionOverlayTest {
|
||||
|
||||
private lateinit var context: Context
|
||||
private lateinit var settings: Settings
|
||||
private lateinit var toolbar: View
|
||||
private lateinit var icon: View
|
||||
private lateinit var session: Session
|
||||
private lateinit var overlay: TrackingProtectionOverlay
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
context = spyk(testContext)
|
||||
settings = mockk(relaxed = true)
|
||||
toolbar = mockk(relaxed = true)
|
||||
icon = mockk(relaxed = true)
|
||||
session = mockk(relaxed = true)
|
||||
|
||||
overlay = TrackingProtectionOverlay(context, settings, toolbar, icon)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no-op when loading`() {
|
||||
every { settings.shouldShowTrackingProtectionOnboarding } returns true
|
||||
every { session.trackerBlockingEnabled } returns true
|
||||
every { session.trackersBlocked } returns listOf(mockk())
|
||||
|
||||
overlay.onLoadingStateChanged(session, loading = true)
|
||||
verify(exactly = 0) { settings.incrementTrackingProtectionOnboardingCount() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no-op when should not show onboarding`() {
|
||||
every { settings.shouldShowTrackingProtectionOnboarding } returns false
|
||||
|
||||
overlay.onLoadingStateChanged(session, loading = false)
|
||||
verify(exactly = 0) { settings.incrementTrackingProtectionOnboardingCount() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no-op when tracking protection disabled`() {
|
||||
every { settings.shouldShowTrackingProtectionOnboarding } returns true
|
||||
every { session.trackerBlockingEnabled } returns false
|
||||
|
||||
overlay.onLoadingStateChanged(session, loading = false)
|
||||
verify(exactly = 0) { settings.incrementTrackingProtectionOnboardingCount() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no-op when no trackers blocked`() {
|
||||
every { settings.shouldShowTrackingProtectionOnboarding } returns true
|
||||
every { session.trackerBlockingEnabled } returns true
|
||||
every { session.trackersBlocked } returns emptyList()
|
||||
|
||||
overlay.onLoadingStateChanged(session, loading = false)
|
||||
verify(exactly = 0) { settings.incrementTrackingProtectionOnboardingCount() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show onboarding when trackers are blocked`() {
|
||||
every { settings.shouldShowTrackingProtectionOnboarding } returns true
|
||||
every { session.trackerBlockingEnabled } returns true
|
||||
every { session.trackersBlocked } returns listOf(mockk())
|
||||
|
||||
overlay.onLoadingStateChanged(session, loading = false)
|
||||
verify { settings.incrementTrackingProtectionOnboardingCount() }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user