1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 package org.mozilla.fenix.components.metrics
7 import android.content.Context
8 import mozilla.components.browser.state.search.SearchEngine
9 import mozilla.components.feature.top.sites.TopSite
10 import org.mozilla.fenix.GleanMetrics.Addons
11 import org.mozilla.fenix.GleanMetrics.AppTheme
12 import org.mozilla.fenix.GleanMetrics.Autoplay
13 import org.mozilla.fenix.GleanMetrics.ContextMenu
14 import org.mozilla.fenix.GleanMetrics.Events
15 import org.mozilla.fenix.GleanMetrics.History
16 import org.mozilla.fenix.GleanMetrics.Logins
17 import org.mozilla.fenix.GleanMetrics.Pocket
18 import org.mozilla.fenix.GleanMetrics.SearchTerms
19 import org.mozilla.fenix.GleanMetrics.TopSites
20 import org.mozilla.fenix.R
21 import org.mozilla.fenix.ext.name
22 import java.util.Locale
27 object OpenedAppFirstRun : Event()
28 object InteractWithSearchURLArea : Event()
29 object DismissedOnboarding : Event()
30 object ClearedPrivateData : Event()
31 object AddBookmark : Event()
32 object CustomTabsClosed : Event()
33 object CustomTabsActionTapped : Event()
34 object CustomTabsMenuOpened : Event()
35 object NormalAndPrivateUriOpened : Event()
36 object HistoryOpened : Event()
37 object HistoryItemShared : Event()
38 object HistoryItemOpened : Event()
39 object HistoryOpenedInNewTab : Event()
40 object HistoryOpenedInNewTabs : Event()
41 object HistoryOpenedInPrivateTab : Event()
42 object HistoryOpenedInPrivateTabs : Event()
43 object HistoryItemRemoved : Event()
44 object HistoryAllItemsRemoved : Event()
45 data class HistoryRecentSearchesTapped(val source: String) : Event() {
46 override val extras = mapOf(History.recentSearchesTappedKeys.pageNumber to source)
48 object HistoryHighlightOpened : Event()
49 object HistorySearchGroupOpened : Event()
50 object HistorySearchTermGroupTapped : Event()
51 object HistorySearchTermGroupOpenTab : Event()
52 object HistorySearchTermGroupRemoveTab : Event()
53 object HistorySearchTermGroupRemoveAll : Event()
54 object HistorySearchIconTapped : Event()
55 object HistorySearchResultTapped : Event()
56 object ReaderModeAvailable : Event()
57 object ReaderModeOpened : Event()
58 object ReaderModeClosed : Event()
59 object ReaderModeAppearanceOpened : Event()
60 object TabMediaPlay : Event()
61 object TabMediaPause : Event()
62 object MediaPlayState : Event()
63 object MediaPauseState : Event()
64 object MediaStopState : Event()
65 object MediaFullscreenState : Event()
66 object MediaPictureInPictureState : Event()
67 object NotificationMediaPlay : Event()
68 object NotificationMediaPause : Event()
69 object TopSiteOpenDefault : Event()
70 object TopSiteOpenGoogle : Event()
71 object TopSiteOpenBaidu : Event()
72 object TopSiteOpenFrecent : Event()
73 object TopSiteOpenPinned : Event()
74 object TopSiteOpenProvided : Event()
75 object TopSiteOpenInNewTab : Event()
76 object TopSiteOpenInPrivateTab : Event()
77 object TopSiteOpenContileInPrivateTab : Event()
78 object TopSiteRemoved : Event()
79 object TopSiteContileSettings : Event()
80 object TopSiteContilePrivacy : Event()
81 object GoogleTopSiteRemoved : Event()
82 object BaiduTopSiteRemoved : Event()
83 object OpenLogins : Event()
84 object OpenOneLogin : Event()
85 object CopyLogin : Event()
86 object DeleteLogin : Event()
87 object EditLogin : Event()
88 object EditLoginSave : Event()
89 object ViewLoginPassword : Event()
90 object WhatsNewTapped : Event()
91 object PocketTopSiteClicked : Event()
92 object PocketTopSiteRemoved : Event()
93 object PocketHomeRecsShown : Event()
94 object PocketHomeRecsDiscoverMoreClicked : Event()
95 object PocketHomeRecsLearnMoreClicked : Event()
96 data class PocketHomeRecsStoryClicked(
98 val storyPosition: Pair<Int, Int>,
100 override val extras: Map<Pocket.homeRecsStoryClickedKeys, String>
102 Pocket.homeRecsStoryClickedKeys.timesShown to timesShown.toString(),
103 Pocket.homeRecsStoryClickedKeys.position to "${storyPosition.first}x${storyPosition.second}"
107 data class PocketHomeRecsCategoryClicked(
108 val categoryname: String,
109 val previousSelectedCategoriesTotal: Int,
110 val isSelectedNextState: Boolean
112 override val extras: Map<Pocket.homeRecsCategoryClickedKeys, String>
114 Pocket.homeRecsCategoryClickedKeys.categoryName to categoryname,
115 Pocket.homeRecsCategoryClickedKeys.selectedTotal to previousSelectedCategoriesTotal.toString(),
116 Pocket.homeRecsCategoryClickedKeys.newState to when (isSelectedNextState) {
118 false -> "deselected"
122 object AddonsOpenInSettings : Event()
123 object VoiceSearchTapped : Event()
124 object SearchWidgetInstalled : Event()
125 object ChangedToDefaultBrowser : Event()
126 object DefaultBrowserNotifTapped : Event()
128 object ProgressiveWebAppOpenFromHomescreenTap : Event()
129 object ProgressiveWebAppInstallAsShortcut : Event()
131 object TabSettingsOpened : Event()
133 object CopyUrlUsed : Event()
135 object SyncedTabOpened : Event()
137 object RecentlyClosedTabsOpenedOld : Event()
138 object HaveOpenTabs : Event()
139 object HaveNoOpenTabs : Event()
141 object ContextMenuCopyTapped : Event()
142 object ContextMenuSearchTapped : Event()
143 object ContextMenuSelectAllTapped : Event()
144 object ContextMenuShareTapped : Event()
146 object SyncedTabSuggestionClicked : Event()
147 object BookmarkSuggestionClicked : Event()
148 object ClipboardSuggestionClicked : Event()
149 object HistorySuggestionClicked : Event()
150 object SearchActionClicked : Event()
151 object SearchSuggestionClicked : Event()
152 object OpenedTabSuggestionClicked : Event()
154 // Set default browser experiment metrics
155 object ToolbarMenuShown : Event()
156 object SetDefaultBrowserToolbarMenuClicked : Event()
158 // Home menu interaction
159 object HomeMenuSettingsItemClicked : Event()
160 object HomeScreenDisplayed : Event()
161 object HomeScreenViewCount : Event()
162 object HomeScreenCustomizedHomeClicked : Event()
165 object BrowserToolbarHomeButtonClicked : Event()
168 object StartOnHomeEnterHomeScreen : Event()
169 object StartOnHomeOpenTabsTray : Event()
172 object ShowAllRecentTabs : Event()
173 object OpenRecentTab : Event()
174 object OpenInProgressMediaTab : Event()
175 object RecentTabsSectionIsVisible : Event()
176 object RecentTabsSectionIsNotVisible : Event()
179 object BookmarkClicked : Event()
180 object ShowAllBookmarks : Event()
181 object RecentBookmarksShown : Event()
182 data class RecentBookmarkCount(val count: Int) : Event()
184 // Recently visited/Recent searches
185 object RecentSearchesGroupDeleted : Event()
188 object AndroidAutofillUnlockSuccessful : Event()
189 object AndroidAutofillUnlockCanceled : Event()
190 object AndroidAutofillSearchDisplayed : Event()
191 object AndroidAutofillSearchItemSelected : Event()
192 object AndroidAutofillConfirmationSuccessful : Event()
193 object AndroidAutofillConfirmationCanceled : Event()
194 object AndroidAutofillRequestWithLogins : Event()
195 object AndroidAutofillRequestWithoutLogins : Event()
198 object CreditCardSaved : Event()
199 object CreditCardDeleted : Event()
200 object CreditCardModified : Event()
201 object CreditCardFormDetected : Event()
202 object CreditCardAutofilled : Event()
203 object CreditCardAutofillPromptShown : Event()
204 object CreditCardAutofillPromptExpanded : Event()
205 object CreditCardAutofillPromptDismissed : Event()
206 object CreditCardManagementAddTapped : Event()
207 object CreditCardManagementCardTapped : Event()
209 // Interaction events with extras
211 data class TopSiteSwipeCarousel(val page: Int) : Event() {
212 override val extras: Map<TopSites.swipeCarouselKeys, String>?
213 get() = hashMapOf(TopSites.swipeCarouselKeys.page to page.toString())
216 data class TopSiteLongPress(val topSite: TopSite) : Event() {
217 override val extras: Map<TopSites.longPressKeys, String>?
218 get() = hashMapOf(TopSites.longPressKeys.type to topSite.name())
221 data class TopSiteContileImpression(val position: Int, val source: Source) : Event() {
222 enum class Source { NEWTAB }
225 data class TopSiteContileClick(val position: Int, val source: Source) : Event() {
226 enum class Source { NEWTAB }
229 data class PreferenceToggled(
230 val preferenceKey: String,
231 val enabled: Boolean,
234 private val booleanPreferenceTelemetryAllowList = listOf(
235 context.getString(R.string.pref_key_show_search_suggestions),
236 context.getString(R.string.pref_key_remote_debugging),
237 context.getString(R.string.pref_key_telemetry),
238 context.getString(R.string.pref_key_tracking_protection),
239 context.getString(R.string.pref_key_search_bookmarks),
240 context.getString(R.string.pref_key_search_browsing_history),
241 context.getString(R.string.pref_key_show_clipboard_suggestions),
242 context.getString(R.string.pref_key_show_search_engine_shortcuts),
243 context.getString(R.string.pref_key_open_links_in_a_private_tab),
244 context.getString(R.string.pref_key_sync_logins),
245 context.getString(R.string.pref_key_sync_bookmarks),
246 context.getString(R.string.pref_key_sync_history),
247 context.getString(R.string.pref_key_show_voice_search),
248 context.getString(R.string.pref_key_show_search_suggestions_in_private)
251 override val extras: Map<Events.preferenceToggledKeys, String>?
253 Events.preferenceToggledKeys.preferenceKey to preferenceKey,
254 Events.preferenceToggledKeys.enabled to enabled.toString()
258 // If the event is not in the allow list, we don't want to track it
259 require(booleanPreferenceTelemetryAllowList.contains(preferenceKey))
263 data class AddonsOpenInToolbarMenu(val addonId: String) : Event() {
264 override val extras: Map<Addons.openAddonInToolbarMenuKeys, String>?
265 get() = hashMapOf(Addons.openAddonInToolbarMenuKeys.addonId to addonId)
268 data class AddonOpenSetting(val addonId: String) : Event() {
269 override val extras: Map<Addons.openAddonSettingKeys, String>?
270 get() = hashMapOf(Addons.openAddonSettingKeys.addonId to addonId)
273 data class OpenedLink(val mode: Mode) : Event() {
274 enum class Mode { NORMAL, PRIVATE }
276 override val extras: Map<Events.openedLinkKeys, String>?
277 get() = hashMapOf(Events.openedLinkKeys.mode to mode.name)
280 data class SaveLoginsSettingChanged(val setting: Setting) : Event() {
281 enum class Setting { NEVER_SAVE, ASK_TO_SAVE }
283 override val extras: Map<Logins.saveLoginsSettingChangedKeys, String>?
284 get() = hashMapOf(Logins.saveLoginsSettingChangedKeys.setting to setting.name)
287 data class SearchBarTapped(val source: Source) : Event() {
288 enum class Source { HOME, BROWSER }
290 override val extras: Map<Events.searchBarTappedKeys, String>?
291 get() = mapOf(Events.searchBarTappedKeys.source to source.name)
294 data class EnteredUrl(val autoCompleted: Boolean) : Event() {
295 override val extras: Map<Events.enteredUrlKeys, String>?
296 get() = mapOf(Events.enteredUrlKeys.autocomplete to autoCompleted.toString())
299 data class PerformedSearch(val eventSource: EventSource) : Event() {
300 sealed class EngineSource {
301 abstract val engine: SearchEngine
302 abstract val isCustom: Boolean
304 data class Default(override val engine: SearchEngine, override val isCustom: Boolean) :
307 data class Shortcut(override val engine: SearchEngine, override val isCustom: Boolean) :
310 // https://github.com/mozilla-mobile/fenix/issues/1607
311 // Sanitize identifiers for custom search engines.
312 val identifier: String
313 get() = if (isCustom) "custom" else engine.id
315 val searchEngine: SearchEngine
316 get() = when (this) {
318 is Shortcut -> engine
321 val descriptor: String
322 get() = when (this) {
323 is Default -> "default"
324 is Shortcut -> "shortcut"
328 sealed class EventSource(open val engineSource: EngineSource) {
329 data class Suggestion(override val engineSource: EngineSource) :
330 EventSource(engineSource)
332 data class Action(override val engineSource: EngineSource) : EventSource(engineSource)
333 data class Widget(override val engineSource: EngineSource) : EventSource(engineSource)
334 data class Shortcut(override val engineSource: EngineSource) : EventSource(engineSource)
335 data class TopSite(override val engineSource: EngineSource) : EventSource(engineSource)
336 data class Other(override val engineSource: EngineSource) : EventSource(engineSource)
338 private val label: String
339 get() = when (this) {
340 is Suggestion -> "suggestion"
341 is Action -> "action"
342 is Widget -> "widget"
343 is Shortcut -> "shortcut"
344 is TopSite -> "topsite"
348 val countLabel: String
349 get() = "${engineSource.identifier.lowercase(Locale.getDefault())}.$label"
351 val sourceLabel: String
352 get() = "${engineSource.descriptor}.$label"
355 enum class SearchAccessPoint {
356 SUGGESTION, ACTION, WIDGET, SHORTCUT, TOPSITE, NONE
359 override val extras: Map<Events.performedSearchKeys, String>?
360 get() = mapOf(Events.performedSearchKeys.source to eventSource.sourceLabel)
363 data class DarkThemeSelected(val source: Source) : Event() {
364 enum class Source { SETTINGS }
366 override val extras: Map<AppTheme.darkThemeSelectedKeys, String>?
367 get() = mapOf(AppTheme.darkThemeSelectedKeys.source to source.name)
370 data class SearchWithAds(val providerName: String) : Event() {
375 data class SearchAdClicked(val keyName: String) : Event() {
380 data class SearchInContent(val keyName: String) : Event() {
385 class ContextMenuItemTapped private constructor(val item: String) : Event() {
386 override val extras: Map<ContextMenu.itemTappedKeys, String>?
387 get() = mapOf(ContextMenu.itemTappedKeys.named to item)
390 fun create(context_item: String) =
391 allowList[context_item]?.let { ContextMenuItemTapped(it) }
393 private val allowList = mapOf(
394 "mozac.feature.contextmenu.open_in_new_tab" to "open_in_new_tab",
395 "mozac.feature.contextmenu.open_in_private_tab" to "open_in_private_tab",
396 "mozac.feature.contextmenu.open_image_in_new_tab" to "open_image_in_new_tab",
397 "mozac.feature.contextmenu.save_image" to "save_image",
398 "mozac.feature.contextmenu.share_link" to "share_link",
399 "mozac.feature.contextmenu.copy_link" to "copy_link",
400 "mozac.feature.contextmenu.copy_image_location" to "copy_image_location",
401 "mozac.feature.contextmenu.share_image" to "share_image"
406 data class AddonInstalled(val addonId: String) : Event()
408 data class BrowserMenuItemTapped(val item: Item) : Event() {
410 SETTINGS, HELP, DESKTOP_VIEW_ON, DESKTOP_VIEW_OFF, FIND_IN_PAGE, NEW_TAB,
411 NEW_PRIVATE_TAB, SHARE, BACK, FORWARD, RELOAD, STOP, OPEN_IN_FENIX,
412 SAVE_TO_COLLECTION, ADD_TO_TOP_SITES, REMOVE_FROM_TOP_SITES, ADD_TO_HOMESCREEN, QUIT, READER_MODE_ON,
413 READER_MODE_OFF, OPEN_IN_APP, BOOKMARK, READER_MODE_APPEARANCE, ADDONS_MANAGER,
414 BOOKMARKS, HISTORY, SYNC_TABS, DOWNLOADS, SET_DEFAULT_BROWSER, SYNC_ACCOUNT
417 override val extras: Map<Events.browserMenuActionKeys, String>?
418 get() = mapOf(Events.browserMenuActionKeys.item to item.toString().lowercase(Locale.ROOT))
421 object AutoPlaySettingVisited : Event()
423 data class AutoPlaySettingChanged(val setting: AutoplaySetting) : Event() {
424 enum class AutoplaySetting {
425 BLOCK_CELLULAR, BLOCK_AUDIO, BLOCK_ALL, ALLOW_ALL
428 override val extras: Map<Autoplay.settingChangedKeys, String>?
429 get() = mapOf(Autoplay.settingChangedKeys.autoplaySetting to setting.toString().lowercase(Locale.ROOT))
432 data class TabViewSettingChanged(val type: Type) : Event() {
433 enum class Type { LIST, GRID }
435 override val extras: Map<Events.tabViewChangedKeys, String>?
436 get() = mapOf(Events.tabViewChangedKeys.type to type.toString().lowercase(Locale.ROOT))
439 data class SearchTermGroupCount(val count: Int) : Event() {
440 override val extras: Map<SearchTerms.numberOfSearchTermGroupKeys, String>
441 get() = hashMapOf(SearchTerms.numberOfSearchTermGroupKeys.count to count.toString())
444 data class AverageTabsPerSearchTermGroup(val averageSize: Double) : Event() {
445 override val extras: Map<SearchTerms.averageTabsPerGroupKeys, String>
446 get() = hashMapOf(SearchTerms.averageTabsPerGroupKeys.count to averageSize.toString())
449 data class SearchTermGroupSizeDistribution(val groupSizes: List<Long>) : Event()
451 object JumpBackInGroupTapped : Event()
455 object WallpaperSettingsOpened : Event()
456 data class WallpaperSelected(val wallpaper: org.mozilla.fenix.wallpapers.Wallpaper) : Event()
457 data class WallpaperSwitched(val wallpaper: org.mozilla.fenix.wallpapers.Wallpaper) : Event()
458 data class ChangeWallpaperWithLogoToggled(val checked: Boolean) : Event()
460 sealed class Messaging(open val messageId: String) : Event() {
461 data class MessageShown(override val messageId: String) : Messaging(messageId)
462 data class MessageDismissed(override val messageId: String) : Messaging(messageId)
463 data class MessageClicked(override val messageId: String, val uuid: String?) :
465 data class MessageMalformed(override val messageId: String) : Messaging(messageId)
466 data class MessageExpired(override val messageId: String) : Messaging(messageId)
469 internal open val extras: Map<*, String>?