[fenix] For https://github.com/mozilla-mobile/fenix/issues/24210: Remove wrapper...
[gecko.git] / mobile / android / fenix / app / src / main / java / org / mozilla / fenix / components / metrics / Event.kt
blobf1c4edc4f4bda77d563f0ab1a2c6705491ee13b0
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
24 sealed class Event {
26     // Interaction Events
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)
47     }
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(
97         val timesShown: Long,
98         val storyPosition: Pair<Int, Int>,
99     ) : Event() {
100         override val extras: Map<Pocket.homeRecsStoryClickedKeys, String>
101             get() = mapOf(
102                 Pocket.homeRecsStoryClickedKeys.timesShown to timesShown.toString(),
103                 Pocket.homeRecsStoryClickedKeys.position to "${storyPosition.first}x${storyPosition.second}"
104             )
105     }
107     data class PocketHomeRecsCategoryClicked(
108         val categoryname: String,
109         val previousSelectedCategoriesTotal: Int,
110         val isSelectedNextState: Boolean
111     ) : Event() {
112         override val extras: Map<Pocket.homeRecsCategoryClickedKeys, String>
113             get() = mapOf(
114                 Pocket.homeRecsCategoryClickedKeys.categoryName to categoryname,
115                 Pocket.homeRecsCategoryClickedKeys.selectedTotal to previousSelectedCategoriesTotal.toString(),
116                 Pocket.homeRecsCategoryClickedKeys.newState to when (isSelectedNextState) {
117                     true -> "selected"
118                     false -> "deselected"
119                 }
120             )
121     }
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()
164     // Browser Toolbar
165     object BrowserToolbarHomeButtonClicked : Event()
167     // Start on Home
168     object StartOnHomeEnterHomeScreen : Event()
169     object StartOnHomeOpenTabsTray : Event()
171     // Recent tabs
172     object ShowAllRecentTabs : Event()
173     object OpenRecentTab : Event()
174     object OpenInProgressMediaTab : Event()
175     object RecentTabsSectionIsVisible : Event()
176     object RecentTabsSectionIsNotVisible : Event()
178     // Recent bookmarks
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()
187     // Android Autofill
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()
197     // Credit cards
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())
214     }
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())
219     }
221     data class TopSiteContileImpression(val position: Int, val source: Source) : Event() {
222         enum class Source { NEWTAB }
223     }
225     data class TopSiteContileClick(val position: Int, val source: Source) : Event() {
226         enum class Source { NEWTAB }
227     }
229     data class PreferenceToggled(
230         val preferenceKey: String,
231         val enabled: Boolean,
232         val context: Context
233     ) : Event() {
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)
249         )
251         override val extras: Map<Events.preferenceToggledKeys, String>?
252             get() = mapOf(
253                 Events.preferenceToggledKeys.preferenceKey to preferenceKey,
254                 Events.preferenceToggledKeys.enabled to enabled.toString()
255             )
257         init {
258             // If the event is not in the allow list, we don't want to track it
259             require(booleanPreferenceTelemetryAllowList.contains(preferenceKey))
260         }
261     }
263     data class AddonsOpenInToolbarMenu(val addonId: String) : Event() {
264         override val extras: Map<Addons.openAddonInToolbarMenuKeys, String>?
265             get() = hashMapOf(Addons.openAddonInToolbarMenuKeys.addonId to addonId)
266     }
268     data class AddonOpenSetting(val addonId: String) : Event() {
269         override val extras: Map<Addons.openAddonSettingKeys, String>?
270             get() = hashMapOf(Addons.openAddonSettingKeys.addonId to addonId)
271     }
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)
278     }
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)
285     }
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)
292     }
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())
297     }
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) :
305                 EngineSource()
307             data class Shortcut(override val engine: SearchEngine, override val isCustom: Boolean) :
308                 EngineSource()
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) {
317                     is Default -> engine
318                     is Shortcut -> engine
319                 }
321             val descriptor: String
322                 get() = when (this) {
323                     is Default -> "default"
324                     is Shortcut -> "shortcut"
325                 }
326         }
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"
345                     is Other -> "other"
346                 }
348             val countLabel: String
349                 get() = "${engineSource.identifier.lowercase(Locale.getDefault())}.$label"
351             val sourceLabel: String
352                 get() = "${engineSource.descriptor}.$label"
353         }
355         enum class SearchAccessPoint {
356             SUGGESTION, ACTION, WIDGET, SHORTCUT, TOPSITE, NONE
357         }
359         override val extras: Map<Events.performedSearchKeys, String>?
360             get() = mapOf(Events.performedSearchKeys.source to eventSource.sourceLabel)
361     }
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)
368     }
370     data class SearchWithAds(val providerName: String) : Event() {
371         val label: String
372             get() = providerName
373     }
375     data class SearchAdClicked(val keyName: String) : Event() {
376         val label: String
377             get() = keyName
378     }
380     data class SearchInContent(val keyName: String) : Event() {
381         val label: String
382             get() = keyName
383     }
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)
389         companion object {
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"
402             )
403         }
404     }
406     data class AddonInstalled(val addonId: String) : Event()
408     data class BrowserMenuItemTapped(val item: Item) : Event() {
409         enum class Item {
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
415         }
417         override val extras: Map<Events.browserMenuActionKeys, String>?
418             get() = mapOf(Events.browserMenuActionKeys.item to item.toString().lowercase(Locale.ROOT))
419     }
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
426         }
428         override val extras: Map<Autoplay.settingChangedKeys, String>?
429             get() = mapOf(Autoplay.settingChangedKeys.autoplaySetting to setting.toString().lowercase(Locale.ROOT))
430     }
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))
437     }
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())
442     }
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())
447     }
449     data class SearchTermGroupSizeDistribution(val groupSizes: List<Long>) : Event()
451     object JumpBackInGroupTapped : Event()
453     sealed class Search
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?) :
464             Messaging(messageId)
465         data class MessageMalformed(override val messageId: String) : Messaging(messageId)
466         data class MessageExpired(override val messageId: String) : Messaging(messageId)
467     }
469     internal open val extras: Map<*, String>?
470         get() = null