Issue #18711: Telemetry for credit card autofill

upstream-sync
Roger Yang 3 years ago committed by mergify[bot]
parent 4a0f29d0a0
commit 5d22bb4707

@ -5173,3 +5173,137 @@ recent_bookmarks:
notification_emails:
- android-probes@mozilla.com
expires: "2022-02-01"
credit_cards:
saved:
type: counter
description: |
A counter of the number of credit cards that have been saved
manually by the user.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
deleted:
type: counter
description: |
A counter of the number of credit cards that have been deleted by
the user.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
modified:
type: event
description: |
A credit card has been modified by the user.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
form_detected:
type: event
description: |
A credit card form was detected.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
autofilled:
type: event
description: |
User has autofilled a credit card.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
autofill_prompt_shown:
type: event
description: |
Credit card autofill prompt was shown.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
autofill_prompt_expanded:
type: event
description: |
Credit card autofill prompt was expanded.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
autofill_prompt_dismissed:
type: event
description: |
Credit card autofill prompt was dismissed.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
management_add_tapped:
type: event
description: |
User has tapped the add button through credit card management settings.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"
management_card_tapped:
type: event
description: |
User has tapped on a saved card through credit card management settings.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/18711
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/20909
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-09-01"

@ -229,6 +229,18 @@ sealed class Event {
object AndroidAutofillRequestWithLogins : Event()
object AndroidAutofillRequestWithoutLogins : Event()
// Credit cards
object CreditCardSaved : Event()
object CreditCardDeleted : Event()
object CreditCardModified : Event()
object CreditCardFormDetected : Event()
object CreditCardAutofilled : Event()
object CreditCardAutofillPromptShown : Event()
object CreditCardAutofillPromptExpanded : Event()
object CreditCardAutofillPromptDismissed : Event()
object CreditCardManagementAddTapped : Event()
object CreditCardManagementCardTapped : Event()
// Interaction events with extras
data class TopSiteSwipeCarousel(val page: Int) : Event() {

@ -20,6 +20,7 @@ import org.mozilla.fenix.GleanMetrics.Collections
import org.mozilla.fenix.GleanMetrics.ContextMenu
import org.mozilla.fenix.GleanMetrics.ContextualMenu
import org.mozilla.fenix.GleanMetrics.CrashReporter
import org.mozilla.fenix.GleanMetrics.CreditCards
import org.mozilla.fenix.GleanMetrics.CustomTab
import org.mozilla.fenix.GleanMetrics.ErrorPage
import org.mozilla.fenix.GleanMetrics.Events
@ -763,6 +764,36 @@ private val Event.wrapper: EventWrapper<*>?
is Event.AndroidAutofillConfirmationSuccessful -> EventWrapper<NoExtraKeys>(
{ AndroidAutofill.confirmSuccessful.record(it) }
)
is Event.CreditCardSaved -> EventWrapper<NoExtraKeys>(
{ CreditCards.saved.add() }
)
is Event.CreditCardDeleted -> EventWrapper<NoExtraKeys>(
{ CreditCards.deleted.add() }
)
is Event.CreditCardModified -> EventWrapper<NoExtraKeys>(
{ CreditCards.modified.record(it) }
)
is Event.CreditCardFormDetected -> EventWrapper<NoExtraKeys>(
{ CreditCards.formDetected.record(it) }
)
is Event.CreditCardAutofillPromptShown -> EventWrapper<NoExtraKeys>(
{ CreditCards.autofillPromptShown.record(it) }
)
is Event.CreditCardAutofillPromptExpanded -> EventWrapper<NoExtraKeys>(
{ CreditCards.autofillPromptExpanded.record(it) }
)
is Event.CreditCardAutofillPromptDismissed -> EventWrapper<NoExtraKeys>(
{ CreditCards.autofillPromptDismissed.record(it) }
)
is Event.CreditCardAutofilled -> EventWrapper<NoExtraKeys>(
{ CreditCards.autofilled.record(it) }
)
is Event.CreditCardManagementAddTapped -> EventWrapper<NoExtraKeys>(
{ CreditCards.managementAddTapped.record(it) }
)
is Event.CreditCardManagementCardTapped -> EventWrapper<NoExtraKeys>(
{ CreditCards.managementCardTapped.record(it) }
)
// Don't record other events in Glean:
is Event.AddBookmark -> null

@ -20,6 +20,7 @@ import mozilla.components.feature.contextmenu.facts.ContextMenuFacts
import mozilla.components.feature.customtabs.CustomTabsFacts
import mozilla.components.feature.media.facts.MediaFacts
import mozilla.components.feature.prompts.dialog.LoginDialogFacts
import mozilla.components.feature.prompts.facts.CreditCardAutofillDialogFacts
import mozilla.components.feature.pwa.ProgressiveWebAppFacts
import mozilla.components.feature.search.telemetry.ads.AdsTelemetry
import mozilla.components.feature.search.telemetry.incontent.InContentTelemetry
@ -162,6 +163,16 @@ internal class ReleaseMetricController(
Component.FEATURE_PROMPTS to LoginDialogFacts.Items.CANCEL -> Event.LoginDialogPromptCancelled
Component.FEATURE_PROMPTS to LoginDialogFacts.Items.NEVER_SAVE -> Event.LoginDialogPromptNeverSave
Component.FEATURE_PROMPTS to LoginDialogFacts.Items.SAVE -> Event.LoginDialogPromptSave
Component.FEATURE_PROMPTS to CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_FORM_DETECTED ->
Event.CreditCardFormDetected
Component.FEATURE_PROMPTS to CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_SUCCESS ->
Event.CreditCardAutofilled
Component.FEATURE_PROMPTS to CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_SHOWN ->
Event.CreditCardAutofillPromptShown
Component.FEATURE_PROMPTS to CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_EXPANDED ->
Event.CreditCardAutofillPromptExpanded
Component.FEATURE_PROMPTS to CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_DISMISSED ->
Event.CreditCardAutofillPromptDismissed
Component.FEATURE_CONTEXTMENU to ContextMenuFacts.Items.ITEM -> {
metadata?.get("item")?.let { Event.ContextMenuItemTapped.create(it.toString()) }

@ -58,7 +58,8 @@ class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_ed
controller = DefaultCreditCardEditorController(
storage = storage,
lifecycleScope = lifecycleScope,
navController = findNavController()
navController = findNavController(),
requireContext().components.analytics.metrics
)
)

@ -49,7 +49,8 @@ class CreditCardsManagementFragment : SecureFragment() {
interactor = DefaultCreditCardsManagementInteractor(
controller = DefaultCreditCardsManagementController(
navController = findNavController()
)
),
requireContext().components.analytics.metrics
)
val binding = ComponentCreditCardsBinding.bind(view)

@ -12,6 +12,8 @@ import kotlinx.coroutines.launch
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment
import org.mozilla.fenix.settings.creditcards.interactor.CreditCardEditorInteractor
@ -55,6 +57,7 @@ class DefaultCreditCardEditorController(
private val storage: AutofillCreditCardsAddressesStorage,
private val lifecycleScope: CoroutineScope,
private val navController: NavController,
private val metrics: MetricController,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : CreditCardEditorController {
@ -69,6 +72,7 @@ class DefaultCreditCardEditorController(
lifecycleScope.launch(Dispatchers.Main) {
navController.popBackStack()
}
metrics.track(Event.CreditCardDeleted)
}
}
@ -79,6 +83,7 @@ class DefaultCreditCardEditorController(
lifecycleScope.launch(Dispatchers.Main) {
navController.popBackStack()
}
metrics.track(Event.CreditCardSaved)
}
}
@ -89,6 +94,7 @@ class DefaultCreditCardEditorController(
lifecycleScope.launch(Dispatchers.Main) {
navController.popBackStack()
}
metrics.track(Event.CreditCardModified)
}
}
}

@ -5,6 +5,8 @@
package org.mozilla.fenix.settings.creditcards.interactor
import mozilla.components.concept.storage.CreditCard
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.creditcards.controller.CreditCardsManagementController
/**
@ -34,14 +36,17 @@ interface CreditCardsManagementInteractor {
* all user interactions.
*/
class DefaultCreditCardsManagementInteractor(
private val controller: CreditCardsManagementController
private val controller: CreditCardsManagementController,
private val metrics: MetricController
) : CreditCardsManagementInteractor {
override fun onSelectCreditCard(creditCard: CreditCard) {
controller.handleCreditCardClicked(creditCard)
metrics.track(Event.CreditCardManagementCardTapped)
}
override fun onAddCreditCardClick() {
controller.handleAddCreditCardClicked()
metrics.track(Event.CreditCardManagementAddTapped)
}
}

@ -17,6 +17,7 @@ import org.junit.runner.RunWith
import org.mozilla.fenix.GleanMetrics.Addons
import org.mozilla.fenix.GleanMetrics.Awesomebar
import org.mozilla.fenix.GleanMetrics.BookmarksManagement
import org.mozilla.fenix.GleanMetrics.CreditCards
import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.History
import org.mozilla.fenix.GleanMetrics.RecentBookmarks
@ -289,4 +290,47 @@ class GleanMetricsServiceTest {
gleanService.track(Event.ShowAllBookmarks)
assertTrue(RecentBookmarks.showAllBookmarks.testHasValue())
}
@Test
fun `credit card events are correctly recorded`() {
assertFalse(CreditCards.saved.testHasValue())
gleanService.track(Event.CreditCardSaved)
assertTrue(CreditCards.saved.testHasValue())
assertFalse(CreditCards.deleted.testHasValue())
gleanService.track(Event.CreditCardDeleted)
assertTrue(CreditCards.deleted.testHasValue())
assertFalse(CreditCards.modified.testHasValue())
gleanService.track(Event.CreditCardModified)
assertTrue(CreditCards.modified.testHasValue())
assertFalse(CreditCards.formDetected.testHasValue())
gleanService.track(Event.CreditCardFormDetected)
assertTrue(CreditCards.formDetected.testHasValue())
assertFalse(CreditCards.autofilled.testHasValue())
gleanService.track(Event.CreditCardAutofilled)
assertTrue(CreditCards.autofilled.testHasValue())
assertFalse(CreditCards.autofillPromptShown.testHasValue())
gleanService.track(Event.CreditCardAutofillPromptShown)
assertTrue(CreditCards.autofillPromptShown.testHasValue())
assertFalse(CreditCards.autofillPromptExpanded.testHasValue())
gleanService.track(Event.CreditCardAutofillPromptExpanded)
assertTrue(CreditCards.autofillPromptExpanded.testHasValue())
assertFalse(CreditCards.autofillPromptDismissed.testHasValue())
gleanService.track(Event.CreditCardAutofillPromptDismissed)
assertTrue(CreditCards.autofillPromptDismissed.testHasValue())
assertFalse(CreditCards.managementAddTapped.testHasValue())
gleanService.track(Event.CreditCardManagementAddTapped)
assertTrue(CreditCards.managementAddTapped.testHasValue())
assertFalse(CreditCards.managementCardTapped.testHasValue())
gleanService.track(Event.CreditCardManagementCardTapped)
assertTrue(CreditCards.managementCardTapped.testHasValue())
}
}

@ -10,6 +10,7 @@ import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.verify
import io.mockk.verifyAll
import mozilla.components.feature.prompts.facts.CreditCardAutofillDialogFacts
import mozilla.components.feature.top.sites.facts.TopSitesFacts
import mozilla.components.support.base.Component
import mozilla.components.support.base.facts.Action
@ -370,4 +371,105 @@ class MetricControllerTest {
assertEquals(settings.enabledAddonsCount, 2)
assertEquals(settings.enabledAddonsList, "test2,test4")
}
@Test
fun `credit card fact should trigger event`() {
val enabled = true
val settings: Settings = mockk(relaxed = true)
val controller = ReleaseMetricController(
services = listOf(dataService1),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { enabled },
settings
)
var fact = Fact(
Component.FEATURE_PROMPTS,
Action.INTERACTION,
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_FORM_DETECTED
)
var event = controller.factToEvent(fact)
assertEquals(event, Event.CreditCardFormDetected)
fact = Fact(
Component.FEATURE_PROMPTS,
Action.INTERACTION,
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_SUCCESS
)
event = controller.factToEvent(fact)
assertEquals(event, Event.CreditCardAutofilled)
fact = Fact(
Component.FEATURE_PROMPTS,
Action.INTERACTION,
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_SHOWN
)
event = controller.factToEvent(fact)
assertEquals(event, Event.CreditCardAutofillPromptShown)
fact = Fact(
Component.FEATURE_PROMPTS,
Action.INTERACTION,
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_EXPANDED
)
event = controller.factToEvent(fact)
assertEquals(event, Event.CreditCardAutofillPromptExpanded)
fact = Fact(
Component.FEATURE_PROMPTS,
Action.INTERACTION,
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_DISMISSED
)
event = controller.factToEvent(fact)
assertEquals(event, Event.CreditCardAutofillPromptDismissed)
}
@Test
fun `credit card events should be sent to enabled service`() {
val controller = ReleaseMetricController(
listOf(dataService1),
isDataTelemetryEnabled = { true },
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { dataService1.shouldTrack(Event.CreditCardSaved) } returns true
every { dataService1.shouldTrack(Event.CreditCardDeleted) } returns true
every { dataService1.shouldTrack(Event.CreditCardModified) } returns true
every { dataService1.shouldTrack(Event.CreditCardFormDetected) } returns true
every { dataService1.shouldTrack(Event.CreditCardAutofilled) } returns true
every { dataService1.shouldTrack(Event.CreditCardAutofillPromptShown) } returns true
every { dataService1.shouldTrack(Event.CreditCardAutofillPromptExpanded) } returns true
every { dataService1.shouldTrack(Event.CreditCardAutofillPromptDismissed) } returns true
every { dataService1.shouldTrack(Event.CreditCardManagementAddTapped) } returns true
every { dataService1.shouldTrack(Event.CreditCardManagementCardTapped) } returns true
controller.start(MetricServiceType.Data)
controller.track(Event.CreditCardSaved)
controller.track(Event.CreditCardDeleted)
controller.track(Event.CreditCardModified)
controller.track(Event.CreditCardFormDetected)
controller.track(Event.CreditCardAutofilled)
controller.track(Event.CreditCardAutofillPromptShown)
controller.track(Event.CreditCardAutofillPromptExpanded)
controller.track(Event.CreditCardAutofillPromptDismissed)
controller.track(Event.CreditCardManagementAddTapped)
controller.track(Event.CreditCardManagementCardTapped)
verify { dataService1.track(Event.CreditCardSaved) }
verify { dataService1.track(Event.CreditCardDeleted) }
verify { dataService1.track(Event.CreditCardModified) }
verify { dataService1.track(Event.CreditCardFormDetected) }
verify { dataService1.track(Event.CreditCardAutofilled) }
verify { dataService1.track(Event.CreditCardAutofillPromptShown) }
verify { dataService1.track(Event.CreditCardAutofillPromptExpanded) }
verify { dataService1.track(Event.CreditCardAutofillPromptDismissed) }
verify { dataService1.track(Event.CreditCardManagementAddTapped) }
verify { dataService1.track(Event.CreditCardManagementCardTapped) }
}
}

@ -23,6 +23,8 @@ import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.creditcards.controller.DefaultCreditCardEditorController
@ExperimentalCoroutinesApi
@ -30,6 +32,7 @@ class DefaultCreditCardEditorControllerTest {
private val storage: AutofillCreditCardsAddressesStorage = mockk(relaxed = true)
private val navController: NavController = mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
private val testCoroutineScope = TestCoroutineScope()
private val testDispatcher = TestCoroutineDispatcher()
@ -46,7 +49,8 @@ class DefaultCreditCardEditorControllerTest {
storage = storage,
lifecycleScope = testCoroutineScope,
navController = navController,
ioDispatcher = testDispatcher
ioDispatcher = testDispatcher,
metrics = metrics
)
)
}
@ -75,6 +79,7 @@ class DefaultCreditCardEditorControllerTest {
coVerify {
storage.deleteCreditCard(creditCardId)
navController.popBackStack()
metrics.track(Event.CreditCardDeleted)
}
}
@ -94,6 +99,7 @@ class DefaultCreditCardEditorControllerTest {
coVerify {
storage.addCreditCard(creditCardFields)
navController.popBackStack()
metrics.track(Event.CreditCardSaved)
}
}
@ -114,6 +120,7 @@ class DefaultCreditCardEditorControllerTest {
coVerify {
storage.updateCreditCard(creditCardId, creditCardFields)
navController.popBackStack()
metrics.track(Event.CreditCardModified)
}
}
}

@ -9,18 +9,21 @@ import io.mockk.verify
import mozilla.components.concept.storage.CreditCard
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.creditcards.controller.CreditCardsManagementController
import org.mozilla.fenix.settings.creditcards.interactor.DefaultCreditCardsManagementInteractor
class DefaultCreditCardsManagementInteractorTest {
private val controller: CreditCardsManagementController = mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
private lateinit var interactor: DefaultCreditCardsManagementInteractor
@Before
fun setup() {
interactor = DefaultCreditCardsManagementInteractor(controller)
interactor = DefaultCreditCardsManagementInteractor(controller, metrics)
}
@Test
@ -28,11 +31,13 @@ class DefaultCreditCardsManagementInteractorTest {
val creditCard: CreditCard = mockk(relaxed = true)
interactor.onSelectCreditCard(creditCard)
verify { controller.handleCreditCardClicked(creditCard) }
verify { metrics.track(Event.CreditCardManagementCardTapped) }
}
@Test
fun onClickAddCreditCard() {
interactor.onAddCreditCardClick()
verify { controller.handleAddCreditCardClicked() }
verify { metrics.track(Event.CreditCardManagementAddTapped) }
}
}

Loading…
Cancel
Save