For #21009 - New Recently closed tabs telemetry

This adds a new `recently_closed_tabs` category with then events for all user
interactions on the screen.

The already existent `events.recently_closed_tabs_opened` is still kept for a
bit more time to still have this data available while the new telemetry ride
the trains but can later be removed in favor of this newly added events.
This commit is contained in:
Mugurell 2021-11-25 13:09:45 +02:00 committed by mergify[bot]
parent e73deb23ac
commit 0be470a104
8 changed files with 300 additions and 7 deletions

View File

@ -358,6 +358,7 @@ events:
description: |
An event that indicates that the user
has accessed recently closed tabs list.
Deprecated in favor of "recently_closed_tabs.opened"
bugs:
- https://github.com/mozilla-mobile/fenix/issues/15366
- https://github.com/mozilla-mobile/fenix/issues/19923
@ -3124,6 +3125,165 @@ history:
- android-probes@mozilla.com
expires: "2022-11-01"
recently_closed_tabs:
opened:
type: event
description: |
User opened the "Recently closed tabs" screen.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
closed:
type: event
description: |
User closed the "Recently closed tabs" screen.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
show_full_history:
type: event
description: |
User tapped "Show full history" to see all history.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
open_tab:
type: event
description: |
User tapped on a tab item to be opened.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
delete_tab:
type: event
description: |
User tapped the delete button of a tab item.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
menu_close:
type: event
description: |
User tapped the close button - "X" to return to the previous screen.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
menu_share:
type: event
description: |
User tapped the share menu option for multi selected tabs.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
menu_delete:
type: event
description: |
User tapped the delete menu option for multi selected tabs.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
menu_open_in_normal_tab:
type: event
description: |
User tapped the "Open in new tab" menu option for multi selected tabs.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
menu_open_in_private_tab:
type: event
description: |
User tapped the "Open in private tab" menu option for multi selected tabs.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
enter_multiselect:
type: event
description: |
User tapped on a tab item to enter multi select mode.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
exit_multiselect:
type: event
description: |
User pressed back or tapped the last selected tab item to exit
multiselect.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21009
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2023-01-31"
reader_mode:
available:
type: event

View File

@ -90,6 +90,18 @@ sealed class Event {
object HistorySearchTermGroupOpenTab : Event()
object HistorySearchTermGroupRemoveTab : Event()
object HistorySearchTermGroupRemoveAll : Event()
object RecentlyClosedTabsOpened : Event()
object RecentlyClosedTabsClosed : Event()
object RecentlyClosedTabsShowFullHistory : Event()
object RecentlyClosedTabsOpenTab : Event()
object RecentlyClosedTabsDeleteTab : Event()
object RecentlyClosedTabsMenuClose : Event()
object RecentlyClosedTabsMenuShare : Event()
object RecentlyClosedTabsMenuDelete : Event()
object RecentlyClosedTabsMenuOpenInNormalTab : Event()
object RecentlyClosedTabsMenuOpenInPrivateTab : Event()
object RecentlyClosedTabsEnterMultiselect : Event()
object RecentlyClosedTabsExitMultiselect : Event()
object ReaderModeAvailable : Event()
object ReaderModeOpened : Event()
object ReaderModeClosed : Event()
@ -235,7 +247,7 @@ sealed class Event {
object SyncedTabOpened : Event()
object RecentlyClosedTabsOpened : Event()
object RecentlyClosedTabsOpenedOld : Event()
object HaveOpenTabs : Event()
object HaveNoOpenTabs : Event()

View File

@ -42,6 +42,7 @@ import org.mozilla.fenix.GleanMetrics.ReaderMode
import org.mozilla.fenix.GleanMetrics.RecentBookmarks
import org.mozilla.fenix.GleanMetrics.RecentSearches
import org.mozilla.fenix.GleanMetrics.RecentTabs
import org.mozilla.fenix.GleanMetrics.RecentlyClosedTabs
import org.mozilla.fenix.GleanMetrics.SearchShortcuts
import org.mozilla.fenix.GleanMetrics.SearchTerms
import org.mozilla.fenix.GleanMetrics.SearchWidget
@ -325,6 +326,42 @@ private val Event.wrapper: EventWrapper<*>?
is Event.HistorySearchTermGroupRemoveAll -> EventWrapper<NoExtraKeys>(
{ History.searchTermGroupRemoveAll.record(it) }
)
is Event.RecentlyClosedTabsOpened -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.opened.record(it) }
)
is Event.RecentlyClosedTabsClosed -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.closed.record(it) }
)
is Event.RecentlyClosedTabsShowFullHistory -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.showFullHistory.record(it) }
)
is Event.RecentlyClosedTabsOpenTab -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.openTab.record(it) }
)
is Event.RecentlyClosedTabsDeleteTab -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.deleteTab.record(it) }
)
is Event.RecentlyClosedTabsMenuClose -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.menuClose.record(it) }
)
is Event.RecentlyClosedTabsMenuShare -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.menuShare.record(it) }
)
is Event.RecentlyClosedTabsMenuDelete -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.menuDelete.record(it) }
)
is Event.RecentlyClosedTabsMenuOpenInNormalTab -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.menuOpenInNormalTab.record(it) }
)
is Event.RecentlyClosedTabsMenuOpenInPrivateTab -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.menuOpenInPrivateTab.record(it) }
)
is Event.RecentlyClosedTabsEnterMultiselect -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.enterMultiselect.record(it) }
)
is Event.RecentlyClosedTabsExitMultiselect -> EventWrapper<NoExtraKeys>(
{ RecentlyClosedTabs.exitMultiselect.record(it) }
)
is Event.CollectionRenamed -> EventWrapper<NoExtraKeys>(
{ Collections.renamed.record(it) }
)
@ -691,7 +728,7 @@ private val Event.wrapper: EventWrapper<*>?
{ Events.syncedTabOpened.record(it) }
)
is Event.RecentlyClosedTabsOpened -> EventWrapper<NoExtraKeys>(
is Event.RecentlyClosedTabsOpenedOld -> EventWrapper<NoExtraKeys>(
{ Events.recentlyClosedTabsOpened.record(it) }
)

View File

@ -101,6 +101,6 @@ class DefaultHistoryController(
HistoryFragmentDirections.actionGlobalRecentlyClosed(),
NavOptions.Builder().setPopUpTo(R.id.recentlyClosedFragment, true).build()
)
metrics.track(Event.RecentlyClosedTabsOpened)
metrics.track(Event.RecentlyClosedTabsOpenedOld)
}
}

View File

@ -15,6 +15,8 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
@Suppress("TooManyFunctions")
interface RecentlyClosedController {
@ -37,6 +39,7 @@ class DefaultRecentlyClosedController(
private val recentlyClosedStore: RecentlyClosedFragmentStore,
private val tabsUseCases: TabsUseCases,
private val activity: HomeActivity,
private val metrics: MetricController,
private val openToBrowser: (item: RecoverableTab, mode: BrowsingMode?) -> Unit
) : RecentlyClosedController {
override fun handleOpen(tab: RecoverableTab, mode: BrowsingMode?) {
@ -44,28 +47,44 @@ class DefaultRecentlyClosedController(
}
override fun handleOpen(tabs: Set<RecoverableTab>, mode: BrowsingMode?) {
if (mode == BrowsingMode.Normal) {
metrics.track(Event.RecentlyClosedTabsMenuOpenInNormalTab)
} else if (mode == BrowsingMode.Private) {
metrics.track(Event.RecentlyClosedTabsMenuOpenInPrivateTab)
}
recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.DeselectAll)
tabs.forEach { tab -> handleOpen(tab, mode) }
}
override fun handleSelect(tab: RecoverableTab) {
if (recentlyClosedStore.state.selectedTabs.isEmpty()) {
metrics.track(Event.RecentlyClosedTabsEnterMultiselect)
}
recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Select(tab))
}
override fun handleDeselect(tab: RecoverableTab) {
if (recentlyClosedStore.state.selectedTabs.size == 1) {
metrics.track(Event.RecentlyClosedTabsExitMultiselect)
}
recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Deselect(tab))
}
override fun handleDelete(tab: RecoverableTab) {
metrics.track(Event.RecentlyClosedTabsDeleteTab)
browserStore.dispatch(RecentlyClosedAction.RemoveClosedTabAction(tab))
}
override fun handleDelete(tabs: Set<RecoverableTab>) {
metrics.track(Event.RecentlyClosedTabsMenuDelete)
recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.DeselectAll)
tabs.forEach { tab -> handleDelete(tab) }
tabs.forEach { tab ->
browserStore.dispatch(RecentlyClosedAction.RemoveClosedTabAction(tab))
}
}
override fun handleNavigateToHistory() {
metrics.track(Event.RecentlyClosedTabsShowFullHistory)
navController.navigate(
RecentlyClosedFragmentDirections.actionGlobalHistoryFragment(),
NavOptions.Builder().setPopUpTo(R.id.historyFragment, true).build()
@ -73,6 +92,7 @@ class DefaultRecentlyClosedController(
}
override fun handleShare(tabs: Set<RecoverableTab>) {
metrics.track(Event.RecentlyClosedTabsMenuShare)
val shareData = tabs.map { ShareData(url = it.url, title = it.title) }
navController.navigate(
RecentlyClosedFragmentDirections.actionGlobalShareFragment(
@ -82,6 +102,8 @@ class DefaultRecentlyClosedController(
}
override fun handleRestore(item: RecoverableTab) {
metrics.track(Event.RecentlyClosedTabsOpenTab)
tabsUseCases.restore(item)
browserStore.dispatch(
@ -95,9 +117,11 @@ class DefaultRecentlyClosedController(
override fun handleBackPressed(): Boolean {
return if (recentlyClosedStore.state.selectedTabs.isNotEmpty()) {
metrics.track(Event.RecentlyClosedTabsExitMultiselect)
recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.DeselectAll)
true
} else {
metrics.track(Event.RecentlyClosedTabsClosed)
false
}
}

View File

@ -25,6 +25,8 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.databinding.FragmentRecentlyClosedTabsBinding
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.setTextColor
@ -41,6 +43,8 @@ class RecentlyClosedFragment : LibraryPageFragment<RecoverableTab>(), UserIntera
private lateinit var recentlyClosedInteractor: RecentlyClosedFragmentInteractor
private lateinit var recentlyClosedController: RecentlyClosedController
private lateinit var metrics: MetricController
override fun onResume() {
super.onResume()
showToolbar(getString(R.string.library_recently_closed_tabs))
@ -64,6 +68,7 @@ class RecentlyClosedFragment : LibraryPageFragment<RecoverableTab>(), UserIntera
return when (item.itemId) {
R.id.close_history -> {
close()
metrics.track(Event.RecentlyClosedTabsMenuClose)
true
}
R.id.share_history_multi_select -> {
@ -89,6 +94,9 @@ class RecentlyClosedFragment : LibraryPageFragment<RecoverableTab>(), UserIntera
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
metrics = requireComponents.analytics.metrics.also {
it.track(Event.RecentlyClosedTabsOpened)
}
}
override fun onCreateView(
@ -111,6 +119,7 @@ class RecentlyClosedFragment : LibraryPageFragment<RecoverableTab>(), UserIntera
recentlyClosedStore = recentlyClosedFragmentStore,
activity = activity as HomeActivity,
tabsUseCases = requireComponents.useCases.tabsUseCases,
metrics = metrics,
openToBrowser = ::openItem
)
recentlyClosedInteractor = RecentlyClosedFragmentInteractor(recentlyClosedController)

View File

@ -142,7 +142,7 @@ class DefaultNavigationInteractor(
navController.navigate(
TabsTrayFragmentDirections.actionGlobalRecentlyClosed()
)
metrics.track(Event.RecentlyClosedTabsOpened)
metrics.track(Event.RecentlyClosedTabsOpenedOld)
}
override fun onShareTabs(tabs: Collection<TabSessionState>) {

View File

@ -7,10 +7,12 @@ package org.mozilla.fenix.library.recentlyclosed
import androidx.navigation.NavController
import androidx.navigation.NavOptions
import io.mockk.Runs
import io.mockk.clearMocks
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.verify
import io.mockk.verifyAll
import kotlinx.coroutines.test.TestCoroutineDispatcher
import mozilla.components.browser.state.action.RecentlyClosedAction
import mozilla.components.browser.state.state.recover.RecoverableTab
@ -25,6 +27,8 @@ import org.junit.runner.RunWith
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.directionsEq
import org.mozilla.fenix.ext.optionsEq
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -37,6 +41,7 @@ class DefaultRecentlyClosedControllerTest {
private val browserStore: BrowserStore = mockk(relaxed = true)
private val recentlyClosedStore: RecentlyClosedFragmentStore = mockk(relaxed = true)
private val tabsUseCases: TabsUseCases = mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
@Before
fun setUp() {
@ -97,6 +102,8 @@ class DefaultRecentlyClosedControllerTest {
assertEquals(tabs[1], actualTabs[1])
assertEquals(BrowsingMode.Normal, actualBrowsingModes[0])
assertEquals(BrowsingMode.Normal, actualBrowsingModes[1])
verifyAll { metrics.track(Event.RecentlyClosedTabsMenuOpenInNormalTab) }
clearMocks(metrics)
actualTabs.clear()
actualBrowsingModes.clear()
@ -108,24 +115,51 @@ class DefaultRecentlyClosedControllerTest {
assertEquals(tabs[1], actualTabs[1])
assertEquals(BrowsingMode.Private, actualBrowsingModes[0])
assertEquals(BrowsingMode.Private, actualBrowsingModes[1])
verifyAll { metrics.track(Event.RecentlyClosedTabsMenuOpenInPrivateTab) }
}
@Test
fun `handle select tab`() {
fun `handle selecting first tab`() {
val selectedTab = createFakeTab()
every { recentlyClosedStore.state.selectedTabs } returns emptySet()
createController().handleSelect(selectedTab)
verify { recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Select(selectedTab)) }
verify { metrics.track(Event.RecentlyClosedTabsEnterMultiselect) }
}
@Test
fun `handle deselect tab`() {
fun `handle selecting a successive tab`() {
val selectedTab = createFakeTab()
every { recentlyClosedStore.state.selectedTabs } returns setOf(mockk())
createController().handleSelect(selectedTab)
verify { recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Select(selectedTab)) }
verify(exactly = 0) { metrics.track(Event.RecentlyClosedTabsEnterMultiselect) }
}
@Test
fun `handle deselect last tab`() {
val deselectedTab = createFakeTab()
every { recentlyClosedStore.state.selectedTabs } returns setOf(deselectedTab)
createController().handleDeselect(deselectedTab)
verify { recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Deselect(deselectedTab)) }
verify { metrics.track(Event.RecentlyClosedTabsExitMultiselect) }
}
@Test
fun `handle deselect a tab from others still selected`() {
val deselectedTab = createFakeTab()
every { recentlyClosedStore.state.selectedTabs } returns setOf(deselectedTab, mockk())
createController().handleDeselect(deselectedTab)
verify { recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.Deselect(deselectedTab)) }
verify(exactly = 0) { metrics.track(Event.RecentlyClosedTabsExitMultiselect) }
}
@Test
@ -137,6 +171,7 @@ class DefaultRecentlyClosedControllerTest {
verify {
browserStore.dispatch(RecentlyClosedAction.RemoveClosedTabAction(item))
}
verify { metrics.track(Event.RecentlyClosedTabsDeleteTab) }
}
@Test
@ -149,6 +184,7 @@ class DefaultRecentlyClosedControllerTest {
browserStore.dispatch(RecentlyClosedAction.RemoveClosedTabAction(tabs[0]))
browserStore.dispatch(RecentlyClosedAction.RemoveClosedTabAction(tabs[1]))
}
verify { metrics.track(Event.RecentlyClosedTabsMenuDelete) }
}
@Test
@ -163,6 +199,7 @@ class DefaultRecentlyClosedControllerTest {
optionsEq(NavOptions.Builder().setPopUpTo(R.id.historyFragment, true).build())
)
}
verify { metrics.track(Event.RecentlyClosedTabsShowFullHistory) }
}
@Test
@ -180,6 +217,7 @@ class DefaultRecentlyClosedControllerTest {
directionsEq(RecentlyClosedFragmentDirections.actionGlobalShareFragment(data))
)
}
verify { metrics.track(Event.RecentlyClosedTabsMenuShare) }
}
@Test
@ -191,6 +229,7 @@ class DefaultRecentlyClosedControllerTest {
dispatcher.advanceUntilIdle()
verify { tabsUseCases.restore.invoke(item, true) }
verify { metrics.track(Event.RecentlyClosedTabsOpenTab) }
}
@Test
@ -200,6 +239,17 @@ class DefaultRecentlyClosedControllerTest {
createController().handleBackPressed()
verify { recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.DeselectAll) }
verifyAll { metrics.track(Event.RecentlyClosedTabsExitMultiselect) }
}
@Test
fun `report closing the fragment when back is pressed`() {
every { recentlyClosedStore.state.selectedTabs } returns emptySet()
createController().handleBackPressed()
verify(exactly = 0) { recentlyClosedStore.dispatch(RecentlyClosedFragmentAction.DeselectAll) }
verifyAll { metrics.track(Event.RecentlyClosedTabsClosed) }
}
private fun createController(
@ -211,6 +261,7 @@ class DefaultRecentlyClosedControllerTest {
recentlyClosedStore,
tabsUseCases,
activity,
metrics,
openToBrowser
)
}