For #17644: Always update add-on's telemetry values before sending metric ping (#18529)

upstream-sync
Roger Yang 3 years ago committed by GitHub
parent e1bf8c75a0
commit 8a7c50bbef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -100,7 +100,8 @@ class Analytics(
AdjustMetricsService(context as Application)
),
isDataTelemetryEnabled = { context.settings().isTelemetryEnabled },
isMarketingDataTelemetryEnabled = { context.settings().isMarketingTelemetryEnabled }
isMarketingDataTelemetryEnabled = { context.settings().isMarketingTelemetryEnabled },
context.settings()
)
}

@ -69,6 +69,7 @@ import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.utils.BrowsersCache
import org.mozilla.fenix.utils.Settings
private class EventWrapper<T : Enum<T>>(
private val recorder: ((Map<T, String>?) -> Unit),
@ -859,11 +860,20 @@ class GleanMetricsService(
// setStartupMetrics is not a fast function. It does not need to be done before we can consider
// ourselves initialized. So, let's do it, well, later.
setStartupMetrics()
setStartupMetrics(context.settings())
}
}
internal fun setStartupMetrics() {
/**
* This function is called before the metrics ping is sent. Part of this function depends on
* shared preferences to be updated so the correct value is sent with the metrics ping.
*
* The reason we're using shared preferences to track some of these values is due to the
* limitations of the metrics ping. Events are only sent in a metrics ping if the user have made
* changes between each ping. However, in some cases we want current values to be sent even if
* the user have not changed anything between pings.
*/
internal fun setStartupMetrics(settings: Settings) {
setPreferenceMetrics()
with(Metrics) {
defaultBrowser.set(browsersCache.all(context).isDefaultBrowser)
@ -873,46 +883,58 @@ class GleanMetricsService(
mozillaProducts.set(mozillaProductDetector.getInstalledMozillaProducts(context))
adjustCampaign.set(context.settings().adjustCampaignId)
adjustAdGroup.set(context.settings().adjustAdGroup)
adjustCreative.set(context.settings().adjustCreative)
adjustNetwork.set(context.settings().adjustNetwork)
adjustCampaign.set(settings.adjustCampaignId)
adjustAdGroup.set(settings.adjustAdGroup)
adjustCreative.set(settings.adjustCreative)
adjustNetwork.set(settings.adjustNetwork)
searchWidgetInstalled.set(context.settings().searchWidgetInstalled)
searchWidgetInstalled.set(settings.searchWidgetInstalled)
val openTabsCount = context.settings().openTabsCount
val openTabsCount = settings.openTabsCount
hasOpenTabs.set(openTabsCount > 0)
if (openTabsCount > 0) {
tabsOpenCount.add(openTabsCount)
}
val topSitesSize = context.settings().topSitesSize
val topSitesSize = settings.topSitesSize
hasTopSites.set(topSitesSize > 0)
if (topSitesSize > 0) {
topSitesCount.add(topSitesSize)
}
val desktopBookmarksSize = context.settings().desktopBookmarksSize
val installedAddonSize = settings.installedAddonsCount
Addons.hasInstalledAddons.set(installedAddonSize > 0)
if (installedAddonSize > 0) {
Addons.installedAddons.set(settings.installedAddonsList.split(','))
}
val enabledAddonSize = settings.enabledAddonsCount
Addons.hasEnabledAddons.set(enabledAddonSize > 0)
if (enabledAddonSize > 0) {
Addons.enabledAddons.set(settings.enabledAddonsList.split(','))
}
val desktopBookmarksSize = settings.desktopBookmarksSize
hasDesktopBookmarks.set(desktopBookmarksSize > 0)
if (desktopBookmarksSize > 0) {
desktopBookmarksCount.add(desktopBookmarksSize)
}
val mobileBookmarksSize = context.settings().mobileBookmarksSize
val mobileBookmarksSize = settings.mobileBookmarksSize
hasMobileBookmarks.set(mobileBookmarksSize > 0)
if (mobileBookmarksSize > 0) {
mobileBookmarksCount.add(mobileBookmarksSize)
}
toolbarPosition.set(
when (context.settings().toolbarPosition) {
when (settings.toolbarPosition) {
ToolbarPosition.BOTTOM -> Event.ToolbarPositionChanged.Position.BOTTOM.name
ToolbarPosition.TOP -> Event.ToolbarPositionChanged.Position.TOP.name
}
)
tabViewSetting.set(context.settings().getTabViewPingString())
closeTabSetting.set(context.settings().getTabTimeoutPingString())
tabViewSetting.set(settings.getTabViewPingString())
closeTabSetting.set(settings.getTabTimeoutPingString())
}
store.value.waitForSelectedOrDefaultSearchEngine { searchEngine ->

@ -34,9 +34,9 @@ import mozilla.components.support.base.facts.Facts
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.webextensions.facts.WebExtensionFacts
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.GleanMetrics.Addons
import org.mozilla.fenix.GleanMetrics.PerfAwesomebar
import org.mozilla.fenix.search.awesomebar.ShortcutsSuggestionProvider
import org.mozilla.fenix.utils.Settings
interface MetricController {
fun start(type: MetricServiceType)
@ -47,13 +47,15 @@ interface MetricController {
fun create(
services: List<MetricsService>,
isDataTelemetryEnabled: () -> Boolean,
isMarketingDataTelemetryEnabled: () -> Boolean
isMarketingDataTelemetryEnabled: () -> Boolean,
settings: Settings
): MetricController {
return if (BuildConfig.TELEMETRY) {
ReleaseMetricController(
services,
isDataTelemetryEnabled,
isMarketingDataTelemetryEnabled
isMarketingDataTelemetryEnabled,
settings
)
} else DebugMetricController()
}
@ -83,7 +85,8 @@ internal class DebugMetricController(
internal class ReleaseMetricController(
private val services: List<MetricsService>,
private val isDataTelemetryEnabled: () -> Boolean,
private val isMarketingDataTelemetryEnabled: () -> Boolean
private val isMarketingDataTelemetryEnabled: () -> Boolean,
private val settings: Settings
) : MetricController {
private var initialized = mutableSetOf<MetricServiceType>()
@ -213,16 +216,16 @@ internal class ReleaseMetricController(
Component.SUPPORT_WEBEXTENSIONS to WebExtensionFacts.Items.WEB_EXTENSIONS_INITIALIZED -> {
metadata?.get("installed")?.let { installedAddons ->
if (installedAddons is List<*>) {
Addons.installedAddons.set(installedAddons.map { it.toString() })
Addons.hasInstalledAddons.set(installedAddons.size > 0)
settings.installedAddonsCount = installedAddons.size
settings.installedAddonsList = installedAddons.joinToString(",")
Leanplum.setUserAttributes(mapOf("installed_addons" to installedAddons.size))
}
}
metadata?.get("enabled")?.let { enabledAddons ->
if (enabledAddons is List<*>) {
Addons.enabledAddons.set(enabledAddons.map { it.toString() })
Addons.hasEnabledAddons.set(enabledAddons.size > 0)
settings.enabledAddonsCount = enabledAddons.size
settings.enabledAddonsList = enabledAddons.joinToString()
Leanplum.setUserAttributes(mapOf("enabled_addons" to enabledAddons.size))
}
}

@ -937,6 +937,38 @@ class Settings(private val appContext: Context) : PreferencesHolder {
0
)
/**
* Storing number of installed add-ons for telemetry purposes
*/
var installedAddonsCount by intPreference(
appContext.getPreferenceKey(R.string.pref_key_installed_addons_count),
0
)
/**
* Storing the list of installed add-ons for telemetry purposes
*/
var installedAddonsList by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_installed_addons_list),
default = ""
)
/**
* Storing number of enabled add-ons for telemetry purposes
*/
var enabledAddonsCount by intPreference(
appContext.getPreferenceKey(R.string.pref_key_enabled_addons_count),
0
)
/**
* Storing the list of enabled add-ons for telemetry purposes
*/
var enabledAddonsList by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_enabled_addons_list),
default = ""
)
private var savedLoginsSortingStrategyString by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy),
default = SavedLoginsSortingStrategyMenu.Item.AlphabeticallySort.strategyString

@ -217,6 +217,12 @@
<string name="pref_key_open_tabs_count" translatable="false">pref_key_open_tabs_count</string>
<!-- Add-on Metrics Values -->
<string name="pref_key_installed_addons_count" translatable="false">pref_key_installed_addons_count</string>
<string name="pref_key_installed_addons_list" translatable="false">pref_key_installed_addons_list</string>
<string name="pref_key_enabled_addons_count" translatable="false">pref_key_enabled_addons_count</string>
<string name="pref_key_enabled_addons_list" translatable="false">pref_key_enabled_addons_list</string>
<string name="pref_key_search_count" translatable="false">pref_key_search_count</string>
<string name="pref_key_mobile_bookmarks_size" translatable="false">pref_key_mobile_bookmarks_size</string>

@ -7,6 +7,7 @@ package org.mozilla.fenix.components.metrics
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.service.glean.testing.GleanTestRule
import mozilla.components.support.test.robolectric.testContext
@ -17,6 +18,7 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
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.Events
@ -24,8 +26,10 @@ import org.mozilla.fenix.GleanMetrics.History
import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
import org.mozilla.fenix.GleanMetrics.SyncedTabs
import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.utils.BrowsersCache
import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class GleanMetricsServiceTest {
@ -48,16 +52,46 @@ class GleanMetricsServiceTest {
@Test
fun `setStartupMetrics sets some base metrics`() {
val expectedAppName = "org.mozilla.fenix"
val settings: Settings = mockk()
every { browsersCache.all(any()).isDefaultBrowser } returns true
every { mozillaProductDetector.getMozillaBrowserDefault(any()) } returns expectedAppName
every { mozillaProductDetector.getInstalledMozillaProducts(any()) } returns listOf(expectedAppName)
gleanService.setStartupMetrics()
every { settings.adjustCampaignId } returns "ID"
every { settings.adjustAdGroup } returns "group"
every { settings.adjustCreative } returns "creative"
every { settings.adjustNetwork } returns "network"
every { settings.searchWidgetInstalled } returns true
every { settings.openTabsCount } returns 1
every { settings.topSitesSize } returns 2
every { settings.installedAddonsCount } returns 3
every { settings.installedAddonsList } returns "test1,test2,test3"
every { settings.enabledAddonsCount } returns 2
every { settings.enabledAddonsList } returns "test1,test2"
every { settings.desktopBookmarksSize } returns 4
every { settings.mobileBookmarksSize } returns 5
every { settings.toolbarPosition } returns ToolbarPosition.BOTTOM
every { settings.getTabViewPingString() } returns "test"
every { settings.getTabTimeoutPingString() } returns "test"
gleanService.setStartupMetrics(settings)
// Verify that browser defaults metrics are set.
assertEquals(true, Metrics.defaultBrowser.testGetValue())
assertEquals(expectedAppName, Metrics.defaultMozBrowser.testGetValue())
assertEquals(listOf(expectedAppName), Metrics.mozillaProducts.testGetValue())
assertEquals("ID", Metrics.adjustCampaign.testGetValue())
assertEquals("group", Metrics.adjustAdGroup.testGetValue())
assertEquals("creative", Metrics.adjustCreative.testGetValue())
assertEquals("network", Metrics.adjustNetwork.testGetValue())
assertEquals(true, Metrics.searchWidgetInstalled.testGetValue())
assertEquals(true, Metrics.hasOpenTabs.testGetValue())
assertEquals(1, Metrics.tabsOpenCount.testGetValue())
assertEquals(true, Metrics.hasTopSites.testGetValue())
assertEquals(2, Metrics.topSitesCount.testGetValue())
assertEquals(true, Addons.hasInstalledAddons.testGetValue())
assertEquals(listOf("test1", "test2", "test3"), Addons.installedAddons.testGetValue())
assertEquals(true, Addons.hasEnabledAddons.testGetValue())
assertEquals(listOf("test1", "test2"), Addons.enabledAddons.testGetValue())
// Verify that search engine defaults are NOT set. This test does
// not mock most of the objects telemetry is collected from.

@ -15,9 +15,11 @@ import mozilla.components.support.base.Component
import mozilla.components.support.base.facts.Action
import mozilla.components.support.base.facts.Fact
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.webextensions.facts.WebExtensionFacts
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.utils.Settings
class MetricControllerTest {
@ -57,7 +59,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
services = listOf(dataService1, marketingService1, dataService2, marketingService2),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { enabled }
isMarketingDataTelemetryEnabled = { enabled },
mockk()
)
controller.start(MetricServiceType.Data)
@ -83,7 +86,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
services = listOf(dataService1),
isDataTelemetryEnabled = { false },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
controller.start(MetricServiceType.Data)
@ -99,7 +103,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
services = listOf(dataService1),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
controller.start(MetricServiceType.Data)
@ -119,7 +124,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
services = listOf(dataService1, marketingService1, dataService2, marketingService2),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { enabled }
isMarketingDataTelemetryEnabled = { enabled },
mockk()
)
controller.start(MetricServiceType.Marketing)
@ -145,7 +151,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
listOf(dataService1, marketingService1),
isDataTelemetryEnabled = { true },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { dataService1.shouldTrack(Event.TabMediaPause) } returns false
every { marketingService1.shouldTrack(Event.TabMediaPause) } returns true
@ -161,7 +168,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
listOf(dataService1, marketingService1),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { dataService1.shouldTrack(Event.TabMediaPause) } returns true
every { marketingService1.shouldTrack(Event.TabMediaPause) } returns true
@ -179,7 +187,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
services = listOf(dataService1),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { enabled }
isMarketingDataTelemetryEnabled = { enabled },
mockk()
)
var fact = Fact(
@ -233,7 +242,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
listOf(marketingService1),
isDataTelemetryEnabled = { true },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { marketingService1.shouldTrack(Event.SyncedTabSuggestionClicked) } returns true
controller.start(MetricServiceType.Marketing)
@ -247,7 +257,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
listOf(marketingService1),
isDataTelemetryEnabled = { true },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { marketingService1.shouldTrack(Event.BookmarkSuggestionClicked) } returns true
every { marketingService1.shouldTrack(Event.ClipboardSuggestionClicked) } returns true
@ -281,7 +292,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
listOf(marketingService1),
isDataTelemetryEnabled = { true },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { marketingService1.shouldTrack(Event.AddBookmark) } returns true
every { marketingService1.shouldTrack(Event.RemoveBookmark) } returns true
@ -336,7 +348,8 @@ class MetricControllerTest {
val controller = ReleaseMetricController(
listOf(marketingService1),
isDataTelemetryEnabled = { true },
isMarketingDataTelemetryEnabled = { true }
isMarketingDataTelemetryEnabled = { true },
mockk()
)
every { marketingService1.shouldTrack(Event.HistoryOpenedInNewTab) } returns true
every { marketingService1.shouldTrack(Event.HistoryOpenedInNewTabs) } returns true
@ -355,4 +368,35 @@ class MetricControllerTest {
verify { marketingService1.track(Event.HistoryOpenedInPrivateTab) }
verify { marketingService1.track(Event.HistoryOpenedInPrivateTabs) }
}
@Test
fun `web extension fact should set value in SharedPreference`() {
val enabled = true
val settings: Settings = mockk(relaxed = true)
val controller = ReleaseMetricController(
services = listOf(dataService1),
isDataTelemetryEnabled = { enabled },
isMarketingDataTelemetryEnabled = { enabled },
settings
)
val fact = Fact(
Component.SUPPORT_WEBEXTENSIONS,
Action.INTERACTION,
WebExtensionFacts.Items.WEB_EXTENSIONS_INITIALIZED,
metadata = mapOf(
"installed" to listOf("test1"),
"enabled" to listOf("test2")
)
)
verify(exactly = 0) { settings.installedAddonsCount = any() }
verify(exactly = 0) { settings.installedAddonsList = any() }
verify(exactly = 0) { settings.enabledAddonsCount = any() }
verify(exactly = 0) { settings.enabledAddonsList = any() }
controller.factToEvent(fact)
verify(exactly = 1) { settings.installedAddonsCount = any() }
verify(exactly = 1) { settings.installedAddonsList = any() }
verify(exactly = 1) { settings.enabledAddonsCount = any() }
verify(exactly = 1) { settings.enabledAddonsList = any() }
}
}

Loading…
Cancel
Save