/* 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.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.widget.ImageView import androidx.core.view.isVisible import androidx.core.view.marginTop import com.google.android.material.appbar.AppBarLayout import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.* 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.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.toolbar.ToolbarPosition 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 metrics: MetricController, private val getToolbar: () -> View ) : Session.Observer { override fun onLoadingStateChanged(session: Session, loading: Boolean) { if (!loading && shouldShowTrackingProtectionOnboarding(session)) { showTrackingProtectionOnboarding() } } private fun shouldShowTrackingProtectionOnboarding(session: Session) = session.trackerBlockingEnabled && session.trackersBlocked.isNotEmpty() && settings.shouldShowTrackingProtectionCfr @Suppress("MagicNumber", "InflateParams") private fun showTrackingProtectionOnboarding() { if (!getToolbar().hasWindowFocus()) return val toolbarPosition = settings.toolbarPosition when (toolbarPosition) { ToolbarPosition.BOTTOM -> { if (getToolbar().translationY > 0) { return } } ToolbarPosition.TOP -> { val appBarLayout = getToolbar().parent as? AppBarLayout appBarLayout?.let { appBar -> if (appBar.y != 0.toFloat()) { return } } } } val trackingOnboardingDialog = object : Dialog(context) { override fun onTouchEvent(event: MotionEvent): Boolean { if (event.action == MotionEvent.ACTION_DOWN) { metrics.track(Event.ContextualHintETPOutsideTap) } return super.onTouchEvent(event) } } val layout = LayoutInflater.from(context) .inflate(R.layout.tracking_protection_onboarding_popup, null) layout.drop_down_triangle.isVisible = toolbarPosition == ToolbarPosition.TOP layout.pop_up_triangle.isVisible = toolbarPosition == ToolbarPosition.BOTTOM layout.onboarding_message.text = context.getString( R.string.etp_onboarding_cfr_message, context.getString(R.string.app_name) ) val closeButton = layout.findViewById(R.id.close_onboarding) closeButton.increaseTapArea(BUTTON_INCREASE_DPS) closeButton.setOnClickListener { metrics.track(Event.ContextualHintETPDismissed) trackingOnboardingDialog.dismiss() } val res = context.resources val triangleWidthPx = res.getDimension(R.dimen.cfr_triangle_height) val triangleMarginStartPx = res.getDimension(R.dimen.cfr_triangle_margin_edge) val toolbar = getToolbar() val trackingProtectionIcon: View = toolbar.findViewById(R.id.mozac_browser_toolbar_tracking_protection_indicator) val xOffset = triangleMarginStartPx + triangleWidthPx / 2 val gravity = Gravity.START or toolbarPosition.androidGravity trackingOnboardingDialog.apply { setContentView(layout) setCancelable(false) // removing title or setting it as an empty string does not prevent a11y services from assigning one setTitle(" ") } trackingOnboardingDialog.window?.let { it.setGravity(gravity) val attr = it.attributes attr.x = (trackingProtectionIcon.x + trackingProtectionIcon.width / 2 - xOffset).toInt() attr.y = (trackingProtectionIcon.y + trackingProtectionIcon.height - trackingProtectionIcon.marginTop).toInt() it.attributes = attr it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) } val etpShield = getToolbar().findViewById(R.id.mozac_browser_toolbar_tracking_protection_indicator) trackingOnboardingDialog.message.setOnClickListener { metrics.track(Event.ContextualHintETPInsideTap) trackingOnboardingDialog.dismiss() etpShield.performClick() } metrics.track(Event.ContextualHintETPDisplayed) trackingOnboardingDialog.show() settings.lastCfrShownTimeInMillis = System.currentTimeMillis() settings.incrementTrackingProtectionOnboardingCount() } private companion object { private const val BUTTON_INCREASE_DPS = 12 } }