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:
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,
+ )
+ }
+}