tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit df1aa20bf35eba413119b3a067626c8e9e948c1f
parent c8c2e970b9c0f93146c018dc540ebbae29913fac
Author: John Oberhauser <j.git-global@obez.io>
Date:   Tue, 16 Dec 2025 16:04:18 +0000

Bug 2004413: Adding telemetry for the Privacy Notice banner on homepage r=android-reviewers,gmalekpour,twhite

Differential Revision: https://phabricator.services.mozilla.com/D276081

Diffstat:
Mmobile/android/fenix/app/metrics.yaml | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt | 2++
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/termsofuse/store/PrivacyNoticeBannerTelemetryMiddleware.kt | 48++++++++++++++++++++++++++++++++++++++++++++++++
Amobile/android/fenix/app/src/test/java/org/mozilla/fenix/termsofuse/store/PrivacyNoticeBannerTelemetryMiddlewareTest.kt | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 193 insertions(+), 0 deletions(-)

diff --git a/mobile/android/fenix/app/metrics.yaml b/mobile/android/fenix/app/metrics.yaml @@ -2342,6 +2342,74 @@ private_browsing_locked: - android-probes@mozilla.com expires: never +privacy_notice_banner: + displayed_date: + type: datetime + lifetime: application + description: The timestamp when the user was shown the privacy notice banner. + time_unit: millisecond + send_in_pings: + - metrics + notification_emails: + - android-probes@mozilla.com + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=2004413 + data_reviews: + - https://phabricator.services.mozilla.com/D276081 + expires: never + + displayed: + type: event + description: The user was shown the privacy notice banner. + notification_emails: + - android-probes@mozilla.com + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=2004413 + data_reviews: + - https://phabricator.services.mozilla.com/D276081 + data_sensitivity: + - interaction + expires: never + + close_clicked: + type: event + description: The user clicked the 'x' to close the banner. + notification_emails: + - android-probes@mozilla.com + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=2004413 + data_reviews: + - https://phabricator.services.mozilla.com/D276081 + data_sensitivity: + - interaction + expires: never + + privacy_notice_link_clicked: + type: event + description: The user clicked the Privacy Notice link on the banner. + notification_emails: + - android-probes@mozilla.com + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=2004413 + data_reviews: + - https://phabricator.services.mozilla.com/D276081 + data_sensitivity: + - interaction + expires: never + + learn_more_link_clicked: + type: event + description: The user clicked the Learn More link on the banner. + notification_emails: + - android-probes@mozilla.com + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=2004413 + data_reviews: + - https://phabricator.services.mozilla.com/D276081 + data_sensitivity: + - interaction + expires: never + custom_review_prompt: prompt_displayed: type: event diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -170,6 +170,7 @@ import org.mozilla.fenix.termsofuse.store.PrivacyNoticeBannerAction import org.mozilla.fenix.termsofuse.store.PrivacyNoticeBannerMiddleware import org.mozilla.fenix.termsofuse.store.PrivacyNoticeBannerState import org.mozilla.fenix.termsofuse.store.PrivacyNoticeBannerStore +import org.mozilla.fenix.termsofuse.store.PrivacyNoticeBannerTelemetryMiddleware import org.mozilla.fenix.termsofuse.store.Surface import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.utils.allowUndo @@ -483,6 +484,7 @@ class HomeFragment : Fragment() { PrivacyNoticeBannerMiddleware( repository = privacyNoticeBannerRepository, ), + PrivacyNoticeBannerTelemetryMiddleware(), ), ) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/termsofuse/store/PrivacyNoticeBannerTelemetryMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/termsofuse/store/PrivacyNoticeBannerTelemetryMiddleware.kt @@ -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.termsofuse.store + +import mozilla.components.lib.state.Middleware +import mozilla.components.lib.state.MiddlewareContext +import org.mozilla.fenix.GleanMetrics.PrivacyNoticeBanner + +/** + * [Middleware] to handle [PrivacyNoticeBannerAction]s telemetry recording. + */ +class PrivacyNoticeBannerTelemetryMiddleware : + Middleware<PrivacyNoticeBannerState, PrivacyNoticeBannerAction> { + + override fun invoke( + context: MiddlewareContext<PrivacyNoticeBannerState, PrivacyNoticeBannerAction>, + next: (PrivacyNoticeBannerAction) -> Unit, + action: PrivacyNoticeBannerAction, + ) { + when (action) { + is PrivacyNoticeBannerAction.OnBannerDisplayed -> { + PrivacyNoticeBanner.displayed.record() + PrivacyNoticeBanner.displayedDate.set() + } + + is PrivacyNoticeBannerAction.OnPrivacyNoticeClicked -> { + PrivacyNoticeBanner.privacyNoticeLinkClicked.record() + } + + is PrivacyNoticeBannerAction.OnLearnMoreClicked -> { + PrivacyNoticeBanner.learnMoreLinkClicked.record() + } + + is PrivacyNoticeBannerAction.OnCloseClicked -> { + PrivacyNoticeBanner.closeClicked.record() + } + + // no-ops + is PrivacyNoticeBannerAction.OnFragmentStopped, + -> { + } + } + + next(action) + } +} diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/termsofuse/store/PrivacyNoticeBannerTelemetryMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/termsofuse/store/PrivacyNoticeBannerTelemetryMiddlewareTest.kt @@ -0,0 +1,75 @@ +/* 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.termsofuse.store + +import io.mockk.mockk +import junit.framework.TestCase.assertNotNull +import junit.framework.TestCase.assertNull +import mozilla.components.lib.state.MiddlewareContext +import mozilla.components.support.test.robolectric.testContext +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.GleanMetrics.PrivacyNoticeBanner +import org.mozilla.fenix.helpers.FenixGleanTestRule +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class PrivacyNoticeBannerTelemetryMiddlewareTest { + + @get:Rule + val gleanTestRule = FenixGleanTestRule(testContext) + + private val context = + mockk<MiddlewareContext<PrivacyNoticeBannerState, PrivacyNoticeBannerAction>>( + relaxed = true, + ) + + @Test + fun `WHEN the OnBannerDisplayed action is received THEN telemetry is recorded`() { + assertNull(PrivacyNoticeBanner.displayed.testGetValue()) + assertNull(PrivacyNoticeBanner.displayedDate.testGetValue()) + + invokeMiddlewareWith(PrivacyNoticeBannerAction.OnBannerDisplayed) + + assertNotNull(PrivacyNoticeBanner.displayed.testGetValue()) + assertNotNull(PrivacyNoticeBanner.displayedDate.testGetValue()) + } + + @Test + fun `WHEN the OnPrivacyNoticeClicked action is received THEN telemetry is recorded`() { + assertNull(PrivacyNoticeBanner.privacyNoticeLinkClicked.testGetValue()) + + invokeMiddlewareWith(PrivacyNoticeBannerAction.OnPrivacyNoticeClicked) + + assertNotNull(PrivacyNoticeBanner.privacyNoticeLinkClicked.testGetValue()) + } + + @Test + fun `WHEN the OnLearnMoreClicked action is received THEN telemetry is recorded`() { + assertNull(PrivacyNoticeBanner.learnMoreLinkClicked.testGetValue()) + + invokeMiddlewareWith(PrivacyNoticeBannerAction.OnLearnMoreClicked) + + assertNotNull(PrivacyNoticeBanner.learnMoreLinkClicked.testGetValue()) + } + + @Test + fun `WHEN the OnCloseClicked action is received THEN telemetry is recorded`() { + assertNull(PrivacyNoticeBanner.closeClicked.testGetValue()) + + invokeMiddlewareWith(PrivacyNoticeBannerAction.OnCloseClicked) + + assertNotNull(PrivacyNoticeBanner.closeClicked.testGetValue()) + } + + private fun invokeMiddlewareWith(action: PrivacyNoticeBannerAction) { + PrivacyNoticeBannerTelemetryMiddleware()( + context = context, + next = {}, + action = action, + ) + } +}