[fenix] For https://github.com/mozilla-mobile/fenix/issues/27698: add set as default growth data
parent
587b7920db
commit
088055743c
@ -0,0 +1,29 @@
|
|||||||
|
package org.mozilla.fenix.components.metrics
|
||||||
|
|
||||||
|
import mozilla.components.lib.state.Middleware
|
||||||
|
import mozilla.components.lib.state.MiddlewareContext
|
||||||
|
import org.mozilla.fenix.components.appstate.AppAction
|
||||||
|
import org.mozilla.fenix.components.appstate.AppState
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A middleware that will map incoming actions to relevant events for [metrics].
|
||||||
|
*/
|
||||||
|
class MetricsMiddleware(
|
||||||
|
private val metrics: MetricController,
|
||||||
|
) : Middleware<AppState, AppAction> {
|
||||||
|
override fun invoke(
|
||||||
|
context: MiddlewareContext<AppState, AppAction>,
|
||||||
|
next: (AppAction) -> Unit,
|
||||||
|
action: AppAction,
|
||||||
|
) {
|
||||||
|
handleAction(action)
|
||||||
|
next(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleAction(action: AppAction) = when (action) {
|
||||||
|
is AppAction.MetricsInitializedAction -> {
|
||||||
|
metrics.track(Event.GrowthData.SetAsDefault)
|
||||||
|
}
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/* 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 android.content.Context
|
||||||
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.mozilla.fenix.ext.settings
|
||||||
|
import org.mozilla.fenix.nimbus.FxNimbus
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface defining functions around persisted local state for certain metrics.
|
||||||
|
*/
|
||||||
|
interface MetricsStorage {
|
||||||
|
/**
|
||||||
|
* Determines whether an [event] should be sent based on locally-stored state.
|
||||||
|
*/
|
||||||
|
suspend fun shouldTrack(event: Event): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates locally-stored state for an [event] that has just been sent.
|
||||||
|
*/
|
||||||
|
suspend fun updateSentState(event: Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultMetricsStorage(
|
||||||
|
context: Context,
|
||||||
|
private val settings: Settings,
|
||||||
|
private val checkDefaultBrowser: () -> Boolean,
|
||||||
|
private val shouldSendGenerally: () -> Boolean = { shouldSendGenerally(context) },
|
||||||
|
private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||||
|
) : MetricsStorage {
|
||||||
|
/**
|
||||||
|
* Checks local state to see whether the [event] should be sent.
|
||||||
|
*/
|
||||||
|
override suspend fun shouldTrack(event: Event): Boolean =
|
||||||
|
withContext(dispatcher) {
|
||||||
|
shouldSendGenerally() && when (event) {
|
||||||
|
Event.GrowthData.SetAsDefault -> {
|
||||||
|
!settings.setAsDefaultGrowthSent && checkDefaultBrowser()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateSentState(event: Event) = withContext(dispatcher) {
|
||||||
|
when (event) {
|
||||||
|
Event.GrowthData.SetAsDefault -> settings.setAsDefaultGrowthSent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
fun shouldSendGenerally(context: Context): Boolean {
|
||||||
|
val installedTime = context.packageManager
|
||||||
|
.getPackageInfo(context.packageName, 0)
|
||||||
|
.firstInstallTime
|
||||||
|
val timeDifference = System.currentTimeMillis() - installedTime
|
||||||
|
val withinWindow = timeDifference in windowStartMillis..windowEndMillis
|
||||||
|
|
||||||
|
return context.settings().adjustCampaignId.isNotEmpty() &&
|
||||||
|
FxNimbus.features.growthData.value().enabled &&
|
||||||
|
withinWindow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/* 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 io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
class DefaultMetricsStorageTest {
|
||||||
|
|
||||||
|
private var checkDefaultBrowser = false
|
||||||
|
private val doCheckDefaultBrowser = { checkDefaultBrowser }
|
||||||
|
private var shouldSendGenerally = true
|
||||||
|
private val doShouldSendGenerally = { shouldSendGenerally }
|
||||||
|
|
||||||
|
private val settings = mockk<Settings>()
|
||||||
|
|
||||||
|
private val dispatcher = StandardTestDispatcher()
|
||||||
|
|
||||||
|
private lateinit var storage: DefaultMetricsStorage
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
checkDefaultBrowser = false
|
||||||
|
shouldSendGenerally = true
|
||||||
|
storage = DefaultMetricsStorage(mockk(), settings, doCheckDefaultBrowser, doShouldSendGenerally, dispatcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN that events should not be generally sent WHEN event would be tracked THEN it is not`() = runTest(dispatcher) {
|
||||||
|
shouldSendGenerally = false
|
||||||
|
checkDefaultBrowser = true
|
||||||
|
every { settings.setAsDefaultGrowthSent } returns false
|
||||||
|
|
||||||
|
val result = storage.shouldTrack(Event.GrowthData.SetAsDefault)
|
||||||
|
|
||||||
|
assertFalse(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN set as default has not been sent and app is not default WHEN checked for sending THEN will not be sent`() = runTest(dispatcher) {
|
||||||
|
every { settings.setAsDefaultGrowthSent } returns false
|
||||||
|
checkDefaultBrowser = false
|
||||||
|
|
||||||
|
val result = storage.shouldTrack(Event.GrowthData.SetAsDefault)
|
||||||
|
|
||||||
|
assertFalse(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN set as default has not been sent and app is default WHEN checked for sending THEN will be sent`() = runTest(dispatcher) {
|
||||||
|
every { settings.setAsDefaultGrowthSent } returns false
|
||||||
|
checkDefaultBrowser = true
|
||||||
|
|
||||||
|
val result = storage.shouldTrack(Event.GrowthData.SetAsDefault)
|
||||||
|
|
||||||
|
assertTrue(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN set as default has been sent and app is default WHEN checked for sending THEN will be not sent`() = runTest(dispatcher) {
|
||||||
|
every { settings.setAsDefaultGrowthSent } returns true
|
||||||
|
checkDefaultBrowser = true
|
||||||
|
|
||||||
|
val result = storage.shouldTrack(Event.GrowthData.SetAsDefault)
|
||||||
|
|
||||||
|
assertFalse(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `WHEN set as default updated THEN settings will be updated accordingly`() = runTest(dispatcher) {
|
||||||
|
val updateSlot = slot<Boolean>()
|
||||||
|
every { settings.setAsDefaultGrowthSent = capture(updateSlot) } returns Unit
|
||||||
|
|
||||||
|
storage.updateSentState(Event.GrowthData.SetAsDefault)
|
||||||
|
|
||||||
|
assertTrue(updateSlot.captured)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue