diff --git a/app/metrics.yaml b/app/metrics.yaml index 9e10d0e8fb..1a0a1b3a3f 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -310,7 +310,7 @@ events: expires: "2021-12-01" synced_tab_opened: type: event - description: > + description: | An event that indicates that a synced tab was opened. bugs: - https://github.com/mozilla-mobile/fenix/issues/15369 @@ -1252,7 +1252,7 @@ metrics: customize_home: most_visited_sites: type: boolean - description: > + description: | An indication of whether the most visited sites are enabled to be displayed send_in_pings: @@ -1269,7 +1269,7 @@ customize_home: expires: "2022-09-20" jump_back_in: type: boolean - description: > + description: | An indication of whether the Jump back in section is enabled to be displayed send_in_pings: @@ -1286,7 +1286,7 @@ customize_home: expires: "2022-09-20" recently_saved: type: boolean - description: > + description: | An indication of whether the recently saved section is enabled to be displayed send_in_pings: @@ -1303,7 +1303,7 @@ customize_home: expires: "2022-09-20" recently_visited: type: boolean - description: > + description: | An indication of whether the Recently visited section is enabled to be displayed send_in_pings: @@ -1320,7 +1320,7 @@ customize_home: expires: "2022-09-20" pocket: type: boolean - description: > + description: | An indication of whether Pocket is enabled to be displayed send_in_pings: - metrics @@ -1336,7 +1336,7 @@ customize_home: expires: "2022-09-20" preference_toggled: type: event - description: > + description: | A user toggles the preference for the home screen items. extra_keys: preference_key: @@ -1362,7 +1362,7 @@ customize_home: preferences: search_suggestions_enabled: type: boolean - description: > + description: | Whether or not the user has search suggestions enabled default: true send_in_pings: @@ -1381,7 +1381,7 @@ preferences: expires: "2022-02-01" remote_debugging_enabled: type: boolean - description: > + description: | Whether or not the user has remote debugging enabled default: false send_in_pings: @@ -1400,7 +1400,7 @@ preferences: expires: "2022-02-01" telemetry_enabled: type: boolean - description: > + description: | Whether or not the user has telemetry enabled. Note we should never receive a "false" value for this since telemetry would not send in that case. @@ -1421,7 +1421,7 @@ preferences: expires: "2022-02-01" enhanced_tracking_protection: type: string - description: > + description: | What type of enhanced tracking protection the user has enabled. "standard," "strict," "custom," or "" (if disabled) default: "standard" @@ -1441,7 +1441,7 @@ preferences: expires: "2022-02-01" bookmarks_suggestion: type: boolean - description: > + description: | Whether or not the user has enabled bookmark search suggestions default: true send_in_pings: @@ -1460,7 +1460,7 @@ preferences: expires: "2022-02-01" browsing_history_suggestion: type: boolean - description: > + description: | Whether or not the user has enabled browsing history suggestions. default: true send_in_pings: @@ -1479,7 +1479,7 @@ preferences: expires: "2022-02-01" clipboard_suggestions_enabled: type: boolean - description: > + description: | Whether or not the user has enabled clipboard search suggestions. default: true send_in_pings: @@ -1498,7 +1498,7 @@ preferences: expires: "2022-02-01" search_shortcuts_enabled: type: boolean - description: > + description: | Whether or not the user has enabled search shortcuts. default: true send_in_pings: @@ -1517,7 +1517,7 @@ preferences: expires: "2022-02-01" signed_in_sync: type: boolean - description: > + description: | Whether or not the user is signed into FxA default: false send_in_pings: @@ -1536,7 +1536,7 @@ preferences: expires: "2022-02-01" sync_items: type: string_list - description: > + description: | The list of items the user has chosen to sync with FxA. default: "" if the user is signed out. Otherwise defaults to whatever is set in their FxA account. New accounts set: @@ -1557,7 +1557,7 @@ preferences: expires: "2022-02-01" voice_search_enabled: type: boolean - description: > + description: | Whether or not the user has enabled the voice search button. default: true send_in_pings: @@ -1576,7 +1576,7 @@ preferences: expires: "2022-02-01" toolbar_position_setting: type: string - description: > + description: | The position of the toolbar default: bottom (defaults to top if the user has accessibility services) send_in_pings: @@ -1595,7 +1595,7 @@ preferences: expires: "2022-02-01" accessibility_services: type: string_list - description: > + description: | Whether or not the user has touch exploration or switch services enabled. These are built into the Android OS, not Fenix prefs. default: "" @@ -1615,7 +1615,7 @@ preferences: expires: "2022-02-01" open_links_in_app_enabled: type: boolean - description: > + description: | Whether or not the user has the open links in apps feature enabled. default: false send_in_pings: @@ -1634,7 +1634,7 @@ preferences: expires: "2022-02-01" user_theme: type: string - description: > + description: | The theme the user has enabled. "light," "dark," "system," or "battery" default: "system" for API 28+, else "light" send_in_pings: @@ -1651,6 +1651,22 @@ preferences: notification_emails: - android-probes@mozilla.com expires: "2022-02-01" + inactive_tabs_enabled: + type: boolean + description: | + Whether or not the user has the inactive tabs feature enabled. + default: true + send_in_pings: + - metrics + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21903 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21908 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-11-01" search.default_engine: code: @@ -2784,6 +2800,61 @@ tabs_tray: notification_emails: - android-probes@mozilla.com expires: "2022-08-01" + has_inactive_tabs: + type: event + description: | + A boolean that indicates if the user has any INACTIVE tabs. + extra_keys: + inactive_tabs_count: + description: "The number of inactive tabs the user currently has." + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21903 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21908 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-11-01" + close_all_inactive_tabs: + type: event + description: | + A user tapped the close all inactive tabs button in the the tabs tray + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21903 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21908 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-11-01" + close_inactive_tab: + type: counter + description: | + A counter that indicates how many INACTIVE tabs a user has closed. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21903 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21908 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-11-01" + open_inactive_tab: + type: counter + description: | + A counter that indicates how many INACTIVE tabs a user has opened. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21903 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21908 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-11-01" collections: renamed: @@ -4190,7 +4261,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a history awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4210,7 +4281,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a bookmarks awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4230,7 +4301,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a search engine awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4250,7 +4321,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a session awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4270,7 +4341,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a synced tabs awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4290,7 +4361,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a clipboard awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4310,7 +4381,7 @@ perf.awesomebar: - metrics type: timing_distribution time_unit: millisecond - description: > + description: | Duration of a shortcuts awesomebar suggestion query. bugs: - https://github.com/mozilla-mobile/android-components/issues/4992 @@ -4368,7 +4439,7 @@ storage.stats: send_in_pings: - metrics type: timing_distribution - description: > + description: | How long it took to query the device for the StorageStats that contain the file size information. The docs say it may be expensive so we want to ensure it's not too expensive. This value is only available on Android @@ -4392,7 +4463,7 @@ storage.stats: send_in_pings: - metrics type: memory_distribution - description: > + description: | The size of the app's APK and related files as installed: this is expected to be larger than download size. This is the output of [StorageStats.getAppBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getAppBytes()) @@ -4419,7 +4490,7 @@ storage.stats: send_in_pings: - metrics type: memory_distribution - description: > + description: | The size of all cached data in the app. This is the output of [StorageStats.getCacheBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getCacheBytes()) so see that for details. This value is only available on Android 8+. @@ -4443,7 +4514,7 @@ storage.stats: send_in_pings: - metrics type: memory_distribution - description: > + description: | The size of all data minus `cache_bytes`. This is the output of [StorageStats.getDataBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getDataBytes()) except we subtract the value of `cache_bytes` so the cache is not measured diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index 7b2aae00ac..9ef01dfc9a 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -691,6 +691,8 @@ open class FenixApplication : LocaleAwareApplication(), Provider { else -> "" } ) + + inactiveTabsEnabled.set(settings.inactiveTabsAreEnabled) } reportHomeScreenMetrics(settings) } diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt index 6b1262f7e0..dd02deed94 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt @@ -164,6 +164,12 @@ sealed class Event { object TabsTrayRecentlyClosedPressed : Event() object TabsTrayInactiveTabsExpanded : Event() object TabsTrayInactiveTabsCollapsed : Event() + data class TabsTrayHasInactiveTabs(val count: Int) : Event() { + override val extras = mapOf(TabsTray.hasInactiveTabsKeys.inactiveTabsCount to count.toString()) + } + object TabsTrayCloseAllInactiveTabs : Event() + data class TabsTrayCloseInactiveTab(val amountClosed: Int = 1) : Event() + object TabsTrayOpenInactiveTab : Event() object ProgressiveWebAppOpenFromHomescreenTap : Event() object ProgressiveWebAppInstallAsShortcut : Event() diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt index b13afb8d45..6b518bdc58 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt @@ -590,6 +590,19 @@ private val Event.wrapper: EventWrapper<*>? is Event.TabsTrayInactiveTabsCollapsed -> EventWrapper( { TabsTray.inactiveTabsCollapsed.record(it) } ) + is Event.TabsTrayHasInactiveTabs -> EventWrapper( + { TabsTray.hasInactiveTabs.record(it) }, + { TabsTray.hasInactiveTabsKeys.valueOf(it) } + ) + is Event.TabsTrayCloseAllInactiveTabs -> EventWrapper( + { TabsTray.closeAllInactiveTabs.record(it) } + ) + is Event.TabsTrayCloseInactiveTab -> EventWrapper( + { TabsTray.closeInactiveTab.add(amountClosed) } + ) + is Event.TabsTrayOpenInactiveTab -> EventWrapper( + { TabsTray.openInactiveTab.add() } + ) is Event.AutoPlaySettingVisited -> EventWrapper( { Autoplay.visitedSetting.record(it) } ) diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt index 8bdee189cd..7c6c388ef0 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt @@ -219,6 +219,7 @@ class DefaultTabsTrayController( } override fun handleDeleteAllInactiveTabs() { + metrics.track(Event.TabsTrayCloseAllInactiveTabs) browserStore.state.inactiveTabs.map { it.id }.let { tabsUseCases.removeTabs(it) } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt index a7b46f72da..073fd545d3 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt @@ -10,6 +10,7 @@ import androidx.recyclerview.widget.RecyclerView import mozilla.components.browser.toolbar.MAX_URI_LENGTH import mozilla.components.concept.tabstray.Tab import org.mozilla.fenix.R +import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.databinding.InactiveFooterItemBinding import org.mozilla.fenix.databinding.InactiveHeaderItemBinding import org.mozilla.fenix.databinding.InactiveTabListItemBinding @@ -108,6 +109,7 @@ sealed class InactiveTabViewHolder(itemView: View) : RecyclerView.ViewHolder(ite val url = tab.url.toShortUrl(components.publicSuffixList).take(MAX_URI_LENGTH) itemView.setOnClickListener { + components.analytics.metrics.track(Event.TabsTrayOpenInactiveTab) browserTrayInteractor.open(tab, featureName) } @@ -118,6 +120,7 @@ sealed class InactiveTabViewHolder(itemView: View) : RecyclerView.ViewHolder(ite R.drawable.mozac_ic_close, R.string.content_description_close_button ) { + components.analytics.metrics.track(Event.TabsTrayCloseInactiveTab()) browserTrayInteractor.close(tab, featureName) } } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/NormalBrowserTrayList.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/NormalBrowserTrayList.kt index 0c3b39af2a..a9188b3144 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/NormalBrowserTrayList.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/NormalBrowserTrayList.kt @@ -38,7 +38,15 @@ class NormalBrowserTrayList @JvmOverloads constructor( private val swipeDelegate = SwipeToDeleteDelegate() private val concatAdapter by lazy { adapter as ConcatAdapter } - private val tabSorter by lazy { TabSorter(context, concatAdapter, context.components.core.store) } + private val tabSorter by lazy { + TabSorter( + context, + context.settings(), + context.components.analytics.metrics, + concatAdapter, + context.components.core.store + ) + } private val inactiveTabsFilter: (TabSessionState) -> Boolean = filter@{ if (!context.settings().inactiveTabsAreEnabled) { return@filter false diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt index de9e1232b8..02d770a981 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt @@ -14,9 +14,12 @@ import mozilla.components.feature.tabs.tabstray.TabsFeature import mozilla.components.support.base.observer.Observable import mozilla.components.support.base.observer.ObserverRegistry import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.tabstray.ext.browserAdapter import org.mozilla.fenix.tabstray.ext.inactiveTabsAdapter import org.mozilla.fenix.tabstray.ext.tabGroupAdapter +import org.mozilla.fenix.utils.Settings import kotlin.math.max /** @@ -24,6 +27,8 @@ import kotlin.math.max */ class TabSorter( private val context: Context, + private val settings: Settings, + private val metrics: MetricController, private val concatAdapter: ConcatAdapter, private val store: BrowserStore ) : TabsTray, Observable by ObserverRegistry() { @@ -36,6 +41,9 @@ class TabSorter( // Inactive tabs val selectedInactiveIndex = inactiveTabs.findSelectedIndex(selectedTabId) concatAdapter.inactiveTabsAdapter.updateTabs((Tabs(inactiveTabs, selectedInactiveIndex))) + if (settings.inactiveTabsAreEnabled) { + metrics.track(Event.TabsTrayHasInactiveTabs(inactiveTabs.size)) + } // Tab groups // We don't need to provide a selectedId, because the [TabGroupAdapter] has that built-in with support from diff --git a/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt b/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt index 92c21aee2a..dab743caa5 100644 --- a/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt +++ b/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt @@ -129,6 +129,7 @@ class FenixApplicationTest { every { settings.showPocketRecommendationsFeature } returns true every { settings.showPocketRecommendationsFeature } returns true every { application.reportHomeScreenMetrics(settings) } just Runs + every { settings.inactiveTabsAreEnabled } returns true application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector) @@ -164,6 +165,7 @@ class FenixApplicationTest { assertEquals("fixed_top", Preferences.toolbarPositionSetting.testGetValue()) assertEquals("standard", Preferences.enhancedTrackingProtection.testGetValue()) assertEquals(listOf("switch", "touch exploration"), Preferences.accessibilityServices.testGetValue()) + assertEquals(true, Preferences.inactiveTabsEnabled.testGetValue()) // Verify that search engine defaults are NOT set. This test does // not mock most of the objects telemetry is collected from. diff --git a/app/src/test/java/org/mozilla/fenix/tabstray/DefaultTabsTrayControllerTest.kt b/app/src/test/java/org/mozilla/fenix/tabstray/DefaultTabsTrayControllerTest.kt index c5dda16aef..025f5617ce 100644 --- a/app/src/test/java/org/mozilla/fenix/tabstray/DefaultTabsTrayControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabstray/DefaultTabsTrayControllerTest.kt @@ -431,6 +431,29 @@ class DefaultTabsTrayControllerTest { } } + @Test + fun `WHEN handleDeleteAllInactiveTabs is called THEN Event#TabsTrayCloseAllInactiveTabs and Event#TabsTrayCloseInactiveTab are added to telemetry`() { + val inactiveTab: TabSessionState = mockk { + every { lastAccess } returns maxActiveTime + every { createdAt } returns 0 + every { id } returns "24" + every { content } returns mockk { + every { private } returns false + } + } + every { browserStore.state } returns mockk() + try { + mockkStatic("mozilla.components.browser.state.selector.SelectorsKt") + every { browserStore.state.inactiveTabs } returns listOf(inactiveTab) + + createController().handleDeleteAllInactiveTabs() + + verify { metrics.track(Event.TabsTrayCloseAllInactiveTabs) } + } finally { + unmockkStatic("mozilla.components.browser.state.selector.SelectorsKt") + } + } + private fun createController( navigateToHomeAndDeleteSession: (String) -> Unit = { }, selectTabPosition: (Int, Boolean) -> Unit = { _, _ -> },