diff --git a/app/src/main/java/org/mozilla/fenix/ads/AdsTelemetry.kt b/app/src/main/java/org/mozilla/fenix/ads/AdsTelemetry.kt index f2bd9f4cb..3db3d9ff4 100644 --- a/app/src/main/java/org/mozilla/fenix/ads/AdsTelemetry.kt +++ b/app/src/main/java/org/mozilla/fenix/ads/AdsTelemetry.kt @@ -96,6 +96,18 @@ class AdsTelemetry(private val metrics: MetricController) { }) } + fun trackAdClickedMetric(sessionUrl: String?, urlPath: List) { + if (sessionUrl == null) { + return + } + val provider = getProviderForUrl(sessionUrl) + provider?.let { + if (it.containsAds(urlPath)) { + metrics.track(Event.SearchAdClicked(it.name)) + } + } + } + private fun getProviderForUrl(url: String): SearchProviderModel? { for (provider in providerList) { if (Regex(provider.regexp).containsMatchIn(url)) { diff --git a/app/src/main/java/org/mozilla/fenix/browser/TelemetrySessionObserver.kt b/app/src/main/java/org/mozilla/fenix/browser/TelemetrySessionObserver.kt new file mode 100644 index 000000000..912b711ba --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/browser/TelemetrySessionObserver.kt @@ -0,0 +1,80 @@ +package org.mozilla.fenix.browser + +import androidx.annotation.VisibleForTesting +import mozilla.components.browser.session.Session +import org.mozilla.fenix.ads.AdsTelemetry +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.components.metrics.MetricController + +class TelemetrySessionObserver( + private val metrics: MetricController, + private val ads: AdsTelemetry +) : Session.Observer { + private var urlLoading: String? = null + @VisibleForTesting + var redirectChain = mutableListOf() + @VisibleForTesting + var originSessionUrl: String? = null + + private val temporaryFix = TemporaryFix() + + override fun onLoadingStateChanged(session: Session, loading: Boolean) { + if (loading) { + urlLoading = session.url + } else if (urlLoading != null && !session.private && temporaryFix.shouldSendEvent(session.url)) { + temporaryFix.eventSentFor = session.url + metrics.track(Event.UriOpened) + } + } + + /** + * When a link is clicked, record its redirect chain as well as origin url + */ + override fun onLoadRequest( + session: Session, + url: String, + triggeredByRedirect: Boolean, + triggeredByWebContent: Boolean + ) { + if (isFirstLinkInRedirectChain(url, session.url)) { + originSessionUrl = session.url + } + if (canStartChain()) { + redirectChain.add(url) + } + } + + private fun canStartChain(): Boolean { + return originSessionUrl != null + } + + private fun isFirstLinkInRedirectChain(url: String, sessionUrl: String): Boolean { + return originSessionUrl == null && url != sessionUrl + } + + /** + * After the redirect chain has finished, check if we encountered an ad on the way and clear + * the stored info for that chain + */ + override fun onUrlChanged(session: Session, url: String) { + ads.trackAdClickedMetric(originSessionUrl, redirectChain) + originSessionUrl = null + redirectChain.clear() + } + + /** + * Currently, [Session.Observer.onLoadingStateChanged] is called multiple times the first + * time a new session loads a page. This is inflating our telemetry numbers, so we need to + * handle it, but we will be able to remove this code when [onLoadingStateChanged] has + * been fixed. + * + * See Fenix #3676 + * See AC https://github.com/mozilla-mobile/android-components/issues/4795 + * TODO remove this class after AC #4795 has been fixed + */ + private class TemporaryFix { + var eventSentFor: String? = null + + fun shouldSendEvent(newUrl: String): Boolean = eventSentFor != newUrl + } +} diff --git a/app/src/main/java/org/mozilla/fenix/browser/UriOpenedObserver.kt b/app/src/main/java/org/mozilla/fenix/browser/UriOpenedObserver.kt index 695e816c2..8b8d8e815 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/UriOpenedObserver.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/UriOpenedObserver.kt @@ -4,62 +4,32 @@ package org.mozilla.fenix.browser -import android.content.Context import androidx.annotation.VisibleForTesting import androidx.fragment.app.FragmentActivity import androidx.lifecycle.LifecycleOwner import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager -import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.ads.AdsTelemetry import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.metrics class UriOpenedObserver( - private val context: Context, private val owner: LifecycleOwner, private val sessionManager: SessionManager, - private val metrics: MetricController + metrics: MetricController, + ads: AdsTelemetry ) : SessionManager.Observer { constructor(activity: FragmentActivity) : this( - activity, activity, activity.components.core.sessionManager, - activity.metrics + activity.metrics, + activity.components.core.ads ) - /** - * Currently, [Session.Observer.onLoadingStateChanged] is called multiple times the first - * time a new session loads a page. This is inflating our telemetry numbers, so we need to - * handle it, but we will be able to remove this code when [onLoadingStateChanged] has - * been fixed. - * - * See Fenix #3676 - * See AC https://github.com/mozilla-mobile/android-components/issues/4795 - * TODO remove this class after AC #4795 has been fixed - */ - private class TemporaryFix { - var eventSentFor: String? = null - - fun shouldSendEvent(newUrl: String): Boolean = eventSentFor != newUrl - } - @VisibleForTesting - internal val singleSessionObserver = object : Session.Observer { - private var urlLoading: String? = null - - private val temporaryFix = TemporaryFix() - - override fun onLoadingStateChanged(session: Session, loading: Boolean) { - if (loading) { - urlLoading = session.url - } else if (urlLoading != null && !session.private && temporaryFix.shouldSendEvent(session.url)) { - temporaryFix.eventSentFor = session.url - metrics.track(Event.UriOpened) - } - } - } + internal val singleSessionObserver = TelemetrySessionObserver(metrics, ads) init { sessionManager.register(this, owner)