mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-17 15:26:23 +00:00
[fenix] For https://github.com/mozilla-mobile/fenix/issues/28428: update growth data with new events
This commit is contained in:
parent
79d4353a69
commit
e84f0ee969
@ -23,14 +23,9 @@ sealed class Event {
|
||||
object SetAsDefault : GrowthData("xgpcgt")
|
||||
|
||||
/**
|
||||
* Event recording the first time Firefox has been resumed in a 24 hour period.
|
||||
* Event recording that an ad was clicked in a search engine results page.
|
||||
*/
|
||||
object FirstAppOpenForDay : GrowthData("41hl22")
|
||||
|
||||
/**
|
||||
* Event recording the first time a URI is loaded in Firefox in a 24 hour period.
|
||||
*/
|
||||
object FirstUriLoadForDay : GrowthData("ja86ek")
|
||||
object SerpAdClicked : GrowthData("e2x17e")
|
||||
|
||||
/**
|
||||
* Event recording the first time Firefox is used 3 days in a row in the first week of install.
|
||||
|
@ -262,6 +262,7 @@ internal class ReleaseMetricController(
|
||||
|
||||
Component.FEATURE_SEARCH to AdsTelemetry.SERP_ADD_CLICKED -> {
|
||||
BrowserSearch.adClicks[value!!].add()
|
||||
track(Event.GrowthData.SerpAdClicked)
|
||||
}
|
||||
Component.FEATURE_SEARCH to AdsTelemetry.SERP_SHOWN_WITH_ADDS -> {
|
||||
BrowserSearch.withAds[value!!].add()
|
||||
|
@ -1,3 +1,7 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.components.metrics
|
||||
|
||||
import mozilla.components.lib.state.Middleware
|
||||
@ -23,7 +27,6 @@ class MetricsMiddleware(
|
||||
private fun handleAction(action: AppAction) = when (action) {
|
||||
is AppAction.ResumedMetricsAction -> {
|
||||
metrics.track(Event.GrowthData.SetAsDefault)
|
||||
metrics.track(Event.GrowthData.FirstAppOpenForDay)
|
||||
metrics.track(Event.GrowthData.FirstWeekSeriesActivity)
|
||||
}
|
||||
else -> Unit
|
||||
|
@ -47,21 +47,20 @@ internal class DefaultMetricsStorage(
|
||||
*/
|
||||
override suspend fun shouldTrack(event: Event): Boolean =
|
||||
withContext(dispatcher) {
|
||||
// The side-effect of storing days of use needs to happen during the first two days after
|
||||
// install, which would normally be skipped by shouldSendGenerally.
|
||||
// The side-effect of storing days of use always needs to happen.
|
||||
updateDaysOfUse()
|
||||
val currentTime = System.currentTimeMillis()
|
||||
shouldSendGenerally() && when (event) {
|
||||
Event.GrowthData.SetAsDefault -> {
|
||||
!settings.setAsDefaultGrowthSent && checkDefaultBrowser()
|
||||
}
|
||||
Event.GrowthData.FirstAppOpenForDay -> {
|
||||
settings.resumeGrowthLastSent.hasBeenMoreThanDaySince()
|
||||
}
|
||||
Event.GrowthData.FirstUriLoadForDay -> {
|
||||
settings.uriLoadGrowthLastSent.hasBeenMoreThanDaySince()
|
||||
currentTime.duringFirstMonth() &&
|
||||
!settings.setAsDefaultGrowthSent &&
|
||||
checkDefaultBrowser()
|
||||
}
|
||||
Event.GrowthData.FirstWeekSeriesActivity -> {
|
||||
shouldTrackFirstWeekActivity()
|
||||
currentTime.duringFirstMonth() && shouldTrackFirstWeekActivity()
|
||||
}
|
||||
Event.GrowthData.SerpAdClicked -> {
|
||||
currentTime.duringFirstMonth() && !settings.adClickGrowthSent
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,15 +70,12 @@ internal class DefaultMetricsStorage(
|
||||
Event.GrowthData.SetAsDefault -> {
|
||||
settings.setAsDefaultGrowthSent = true
|
||||
}
|
||||
Event.GrowthData.FirstAppOpenForDay -> {
|
||||
settings.resumeGrowthLastSent = System.currentTimeMillis()
|
||||
}
|
||||
Event.GrowthData.FirstUriLoadForDay -> {
|
||||
settings.uriLoadGrowthLastSent = System.currentTimeMillis()
|
||||
}
|
||||
Event.GrowthData.FirstWeekSeriesActivity -> {
|
||||
settings.firstWeekSeriesGrowthSent = true
|
||||
}
|
||||
Event.GrowthData.SerpAdClicked -> {
|
||||
settings.adClickGrowthSent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,13 +83,13 @@ internal class DefaultMetricsStorage(
|
||||
val daysOfUse = settings.firstWeekDaysOfUseGrowthData
|
||||
val currentDate = Calendar.getInstance(Locale.US)
|
||||
val currentDateString = dateFormatter.format(currentDate.time)
|
||||
if (currentDate.timeInMillis.withinFirstWeek() && daysOfUse.none { it == currentDateString }) {
|
||||
if (currentDate.timeInMillis.duringFirstWeek() && daysOfUse.none { it == currentDateString }) {
|
||||
settings.firstWeekDaysOfUseGrowthData = daysOfUse + currentDateString
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldTrackFirstWeekActivity(): Boolean = Result.runCatching {
|
||||
if (!System.currentTimeMillis().withinFirstWeek() || settings.firstWeekSeriesGrowthSent) {
|
||||
if (!System.currentTimeMillis().duringFirstWeek() || settings.firstWeekSeriesGrowthSent) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -121,14 +117,13 @@ internal class DefaultMetricsStorage(
|
||||
return false
|
||||
}.getOrDefault(false)
|
||||
|
||||
private fun Long.hasBeenMoreThanDaySince(): Boolean =
|
||||
System.currentTimeMillis() - this > dayMillis
|
||||
|
||||
private fun Long.toCalendar(): Calendar = Calendar.getInstance(Locale.US).also { calendar ->
|
||||
calendar.timeInMillis = this
|
||||
}
|
||||
|
||||
private fun Long.withinFirstWeek() = this < getInstalledTime() + fullWeekMillis
|
||||
private fun Long.duringFirstWeek() = this < getInstalledTime() + fullWeekMillis
|
||||
|
||||
private fun Long.duringFirstMonth() = this < getInstalledTime() + shortestMonthMillis
|
||||
|
||||
private fun Calendar.createNextDay() = (this.clone() as Calendar).also { calendar ->
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 1)
|
||||
@ -136,8 +131,7 @@ internal class DefaultMetricsStorage(
|
||||
|
||||
companion object {
|
||||
private const val dayMillis: Long = 1000 * 60 * 60 * 24
|
||||
private const val windowStartMillis: Long = dayMillis * 2
|
||||
private const val windowEndMillis: Long = dayMillis * 28
|
||||
private const val shortestMonthMillis: Long = dayMillis * 28
|
||||
|
||||
// Note this is 8 so that recording of FirstWeekSeriesActivity happens throughout the length
|
||||
// of the 7th day after install
|
||||
@ -146,17 +140,11 @@ internal class DefaultMetricsStorage(
|
||||
/**
|
||||
* Determines whether events should be tracked based on some general criteria:
|
||||
* - user has installed as a result of a campaign
|
||||
* - user is within 2-28 days of install
|
||||
* - tracking is still enabled through Nimbus
|
||||
*/
|
||||
fun shouldSendGenerally(context: Context): Boolean {
|
||||
val installedTime = getInstalledTime(context)
|
||||
val timeDifference = System.currentTimeMillis() - installedTime
|
||||
val withinWindow = timeDifference in windowStartMillis..windowEndMillis
|
||||
|
||||
return context.settings().adjustCampaignId.isNotEmpty() &&
|
||||
FxNimbus.features.growthData.value().enabled &&
|
||||
withinWindow
|
||||
FxNimbus.features.growthData.value().enabled
|
||||
}
|
||||
|
||||
fun getInstalledTime(context: Context): Long = context.packageManager
|
||||
|
@ -21,7 +21,6 @@ import mozilla.components.support.base.android.Clock
|
||||
import mozilla.components.support.base.log.logger.Logger
|
||||
import org.mozilla.fenix.GleanMetrics.Events
|
||||
import org.mozilla.fenix.GleanMetrics.Metrics
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.components.metrics.MetricController
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import org.mozilla.fenix.GleanMetrics.EngineTab as EngineMetrics
|
||||
@ -60,9 +59,6 @@ class TelemetryMiddleware(
|
||||
val tab = context.state.findTabOrCustomTab(action.tabId)
|
||||
onEngineSessionKilled(context.state, tab)
|
||||
}
|
||||
is EngineAction.LoadUrlAction -> {
|
||||
metrics.track(Event.GrowthData.FirstUriLoadForDay)
|
||||
}
|
||||
else -> {
|
||||
// no-op
|
||||
}
|
||||
|
@ -1503,16 +1503,6 @@ class Settings(private val appContext: Context) : PreferencesHolder {
|
||||
default = false,
|
||||
)
|
||||
|
||||
var resumeGrowthLastSent by longPreference(
|
||||
key = appContext.getPreferenceKey(R.string.pref_key_growth_resume_last_sent),
|
||||
default = 0,
|
||||
)
|
||||
|
||||
var uriLoadGrowthLastSent by longPreference(
|
||||
key = appContext.getPreferenceKey(R.string.pref_key_growth_uri_load_last_sent),
|
||||
default = 0,
|
||||
)
|
||||
|
||||
var firstWeekSeriesGrowthSent by booleanPreference(
|
||||
key = appContext.getPreferenceKey(R.string.pref_key_growth_first_week_series_sent),
|
||||
default = false,
|
||||
@ -1522,4 +1512,9 @@ class Settings(private val appContext: Context) : PreferencesHolder {
|
||||
key = appContext.getPreferenceKey(R.string.pref_key_growth_first_week_days_of_use),
|
||||
default = setOf(),
|
||||
)
|
||||
|
||||
var adClickGrowthSent by booleanPreference(
|
||||
key = appContext.getPreferenceKey(R.string.pref_key_growth_ad_click_sent),
|
||||
default = false,
|
||||
)
|
||||
}
|
||||
|
@ -318,8 +318,7 @@
|
||||
|
||||
<!-- Growth Data -->
|
||||
<string name="pref_key_growth_set_as_default" translatable="false">pref_key_growth_set_as_default</string>
|
||||
<string name="pref_key_growth_resume_last_sent" translatable="false">pref_key_growth_last_resumed</string>
|
||||
<string name="pref_key_growth_uri_load_last_sent" translatable="false">pref_key_growth_uri_load_last_sent</string>
|
||||
<string name="pref_key_growth_first_week_series_sent" translatable="false">pref_key_growth_first_week_series_sent</string>
|
||||
<string name="pref_key_growth_first_week_days_of_use" translatable="false">pref_key_growth_first_week_days_of_use</string>
|
||||
<string name="pref_key_growth_ad_click_sent" translatable="false">pref_key_growth_ad_click_sent</string>
|
||||
</resources>
|
||||
|
@ -100,68 +100,6 @@ class DefaultMetricsStorageTest {
|
||||
assertTrue(updateSlot.captured)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN that it has been less than 24 hours since last resumed sent WHEN checked for sending THEN will not be sent`() = runTest(dispatcher) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
every { settings.resumeGrowthLastSent } returns currentTime
|
||||
|
||||
val result = storage.shouldTrack(Event.GrowthData.FirstAppOpenForDay)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN that it has been more than 24 hours since last resumed sent WHEN checked for sending THEN will be sent`() = runTest(dispatcher) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
every { settings.resumeGrowthLastSent } returns currentTime - 1000 * 60 * 60 * 24 * 2
|
||||
|
||||
val result = storage.shouldTrack(Event.GrowthData.FirstAppOpenForDay)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN last resumed state updated THEN settings updated accordingly`() = runTest(dispatcher) {
|
||||
val updateSlot = slot<Long>()
|
||||
every { settings.resumeGrowthLastSent } returns 0
|
||||
every { settings.resumeGrowthLastSent = capture(updateSlot) } returns Unit
|
||||
|
||||
storage.updateSentState(Event.GrowthData.FirstAppOpenForDay)
|
||||
|
||||
assertTrue(updateSlot.captured > 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN that it has been less than 24 hours since uri load sent WHEN checked for sending THEN will not be sent`() = runTest(dispatcher) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
every { settings.uriLoadGrowthLastSent } returns currentTime
|
||||
|
||||
val result = storage.shouldTrack(Event.GrowthData.FirstUriLoadForDay)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN that it has been more than 24 hours since uri load sent WHEN checked for sending THEN will be sent`() = runTest(dispatcher) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
every { settings.uriLoadGrowthLastSent } returns currentTime - 1000 * 60 * 60 * 24 * 2
|
||||
|
||||
val result = storage.shouldTrack(Event.GrowthData.FirstUriLoadForDay)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN uri load updated THEN settings updated accordingly`() = runTest(dispatcher) {
|
||||
val updateSlot = slot<Long>()
|
||||
every { settings.uriLoadGrowthLastSent } returns 0
|
||||
every { settings.uriLoadGrowthLastSent = capture(updateSlot) } returns Unit
|
||||
|
||||
storage.updateSentState(Event.GrowthData.FirstUriLoadForDay)
|
||||
|
||||
assertTrue(updateSlot.captured > 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN that app has been used for less than 3 days in a row WHEN checked for first week activity THEN event will not be sent`() = runTest(dispatcher) {
|
||||
val tomorrow = calendarStart.createNextDay()
|
||||
@ -273,6 +211,24 @@ class DefaultMetricsStorageTest {
|
||||
assertFalse(captureSlot.isCaptured)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN serp ad clicked event already sent WHEN checking to track serp ad clicked THEN event will not be sent`() = runTest(dispatcher) {
|
||||
every { settings.adClickGrowthSent } returns true
|
||||
|
||||
val result = storage.shouldTrack(Event.GrowthData.SerpAdClicked)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN serp ad clicked event not sent WHEN checking to track serp ad clicked THEN event will be sent`() = runTest(dispatcher) {
|
||||
every { settings.adClickGrowthSent } returns false
|
||||
|
||||
val result = storage.shouldTrack(Event.GrowthData.SerpAdClicked)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
private fun Calendar.copy() = clone() as Calendar
|
||||
private fun Calendar.createNextDay() = copy().apply {
|
||||
add(Calendar.DAY_OF_MONTH, 1)
|
||||
|
@ -6,7 +6,6 @@ package org.mozilla.fenix.telemetry
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.state.action.ContentAction
|
||||
import mozilla.components.browser.state.action.EngineAction
|
||||
import mozilla.components.browser.state.action.TabListAction
|
||||
@ -33,7 +32,6 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.GleanMetrics.Events
|
||||
import org.mozilla.fenix.GleanMetrics.Metrics
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.components.metrics.MetricController
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
@ -352,13 +350,6 @@ class TelemetryMiddlewareTest {
|
||||
assertNull(EngineMetrics.killForegroundAge.testGetValue())
|
||||
assertEquals(600_000_000, EngineMetrics.killBackgroundAge.testGetValue()!!.sum)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN uri loaded to engine THEN matching event is sent to metrics`() {
|
||||
store.dispatch(EngineAction.LoadUrlAction("", "")).joinBlocking()
|
||||
|
||||
verify { metrics.track(Event.GrowthData.FirstUriLoadForDay) }
|
||||
}
|
||||
}
|
||||
|
||||
internal class FakeClock : Clock.Delegate {
|
||||
|
Loading…
Reference in New Issue
Block a user