* For #23503: Respect studies pref and telemetry enabled pref when manually opting in to studies * Add button to snackbar in nimbus secret settings that allows user to go directly to their data collection prefs * Remove refactoring Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
280afc9d0b
commit
0b981dde5f
|
@ -10,6 +10,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -47,6 +48,8 @@ class NimbusBranchesFragment : Fragment() {
|
|||
}
|
||||
|
||||
controller = NimbusBranchesController(
|
||||
context = requireContext(),
|
||||
navController = findNavController(),
|
||||
nimbusBranchesStore = nimbusBranchesStore,
|
||||
experiments = requireContext().components.analytics.experiments,
|
||||
experimentId = args.experimentId
|
||||
|
|
|
@ -4,15 +4,22 @@
|
|||
|
||||
package org.mozilla.fenix.nimbus.controller
|
||||
|
||||
import android.content.Context
|
||||
import androidx.navigation.NavController
|
||||
import mozilla.components.service.nimbus.NimbusApi
|
||||
import mozilla.components.service.nimbus.ui.NimbusBranchesAdapterDelegate
|
||||
import org.mozilla.experiments.nimbus.Branch
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.components.FenixSnackbar
|
||||
import org.mozilla.fenix.ext.getRootView
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.nimbus.NimbusBranchesAction
|
||||
import org.mozilla.fenix.nimbus.NimbusBranchesFragmentDirections
|
||||
import org.mozilla.fenix.nimbus.NimbusBranchesStore
|
||||
|
||||
/**
|
||||
* [NimbusBranchesFragment] controller. This implements [NimbusBranchesAdapterDelegate] to handle
|
||||
* interactions with a Nimbus branch item.
|
||||
* interactions with a Nimbus branch.
|
||||
*
|
||||
* @param nimbusBranchesStore An instance of [NimbusBranchesStore] for dispatching
|
||||
* [NimbusBranchesAction]s.
|
||||
|
@ -20,12 +27,41 @@ import org.mozilla.fenix.nimbus.NimbusBranchesStore
|
|||
* @param experimentId The string experiment-id or "slug" for a Nimbus experiment.
|
||||
*/
|
||||
class NimbusBranchesController(
|
||||
private val context: Context,
|
||||
private val navController: NavController,
|
||||
private val nimbusBranchesStore: NimbusBranchesStore,
|
||||
private val experiments: NimbusApi,
|
||||
private val experimentId: String
|
||||
) : NimbusBranchesAdapterDelegate {
|
||||
|
||||
override fun onBranchItemClicked(branch: Branch) {
|
||||
val telemetryEnabled = context.settings().isTelemetryEnabled
|
||||
val experimentsEnabled = context.settings().isExperimentationEnabled
|
||||
|
||||
updateOptInState(branch)
|
||||
|
||||
if (!telemetryEnabled && !experimentsEnabled) {
|
||||
val snackbarText = context.getString(R.string.experiments_snackbar)
|
||||
val buttonText = context.getString(R.string.experiments_snackbar_button)
|
||||
context.getRootView()?.let { v ->
|
||||
FenixSnackbar.make(
|
||||
view = v,
|
||||
FenixSnackbar.LENGTH_LONG,
|
||||
isDisplayedWithBrowserToolbar = false
|
||||
)
|
||||
.setText(snackbarText)
|
||||
.setAction(buttonText) {
|
||||
navController.navigate(
|
||||
NimbusBranchesFragmentDirections
|
||||
.actionNimbusBranchesFragmentToDataChoicesFragment()
|
||||
)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateOptInState(branch: Branch) {
|
||||
nimbusBranchesStore.dispatch(
|
||||
if (experiments.getExperimentBranch(experimentId) != branch.slug) {
|
||||
experiments.optInWithBranch(experimentId, branch.slug)
|
||||
|
|
|
@ -1160,6 +1160,14 @@
|
|||
<argument
|
||||
android:name="experimentName"
|
||||
app:argType="string" />
|
||||
<action
|
||||
android:id="@+id/action_nimbusBranchesFragment_to_dataChoicesFragment"
|
||||
app:destination="@id/dataChoicesFragment"
|
||||
app:enterAnim="@anim/slide_in_right"
|
||||
app:exitAnim="@anim/slide_out_left"
|
||||
app:popEnterAnim="@anim/slide_in_left"
|
||||
app:popExitAnim="@anim/slide_out_right"
|
||||
app:popUpTo="@id/settingsFragment" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
|
||||
|
|
|
@ -1763,4 +1763,9 @@
|
|||
<string name="pocket_stories_feature_caption">Part of the Firefox family. %s</string>
|
||||
<!-- Clickable text for opening an external link for more information about Pocket. -->
|
||||
<string name="pocket_stories_feature_learn_more">Learn more</string>
|
||||
|
||||
<!-- Snackbar message for enrolling in a Nimbus experiment from the secret settings when Studies preference is Off.-->
|
||||
<string name="experiments_snackbar">Enable telemetry to send data.</string>
|
||||
<!-- Snackbar button text to navigate to telemetry settings.-->
|
||||
<string name="experiments_snackbar_button">Go to settings</string>
|
||||
</resources>
|
||||
|
|
|
@ -4,32 +4,196 @@
|
|||
|
||||
package org.mozilla.fenix.nimbus
|
||||
|
||||
import android.R
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.NavController
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.verify
|
||||
import io.mockk.verifyAll
|
||||
import mozilla.components.service.nimbus.NimbusApi
|
||||
import mozilla.components.support.test.libstate.ext.waitUntilIdle
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.experiments.nimbus.Branch
|
||||
import org.mozilla.fenix.components.Components
|
||||
import org.mozilla.fenix.components.FenixSnackbar
|
||||
import org.mozilla.fenix.components.metrics.MetricController
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.getRootView
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.nimbus.controller.NimbusBranchesController
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class NimbusBranchesControllerTest {
|
||||
|
||||
private val experiments: NimbusApi = mockk(relaxed = true)
|
||||
private val experimentId = "id"
|
||||
|
||||
private lateinit var controller: NimbusBranchesController
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var nimbusBranchesStore: NimbusBranchesStore
|
||||
private lateinit var settings: Settings
|
||||
private lateinit var activity: Context
|
||||
private lateinit var components: Components
|
||||
private lateinit var metrics: MetricController
|
||||
private lateinit var snackbar: FenixSnackbar
|
||||
private lateinit var rootView: View
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
components = mockk(relaxed = true)
|
||||
settings = mockk(relaxed = true)
|
||||
metrics = mockk(relaxed = true)
|
||||
snackbar = mockk(relaxed = true)
|
||||
navController = mockk(relaxed = true)
|
||||
|
||||
rootView = mockk<ViewGroup>(relaxed = true)
|
||||
activity = mockk<Activity>(relaxed = true) {
|
||||
every { findViewById<View>(R.id.content) } returns rootView
|
||||
every { getRootView() } returns rootView
|
||||
}
|
||||
|
||||
mockkObject(FenixSnackbar)
|
||||
every { FenixSnackbar.make(any(), any(), any(), any()) } returns snackbar
|
||||
|
||||
every { activity.settings() } returns settings
|
||||
every { activity.components.analytics.metrics } returns metrics
|
||||
|
||||
every { navController.currentDestination } returns mockk {
|
||||
every { id } returns org.mozilla.fenix.R.id.nimbusBranchesFragment
|
||||
}
|
||||
|
||||
nimbusBranchesStore = NimbusBranchesStore(NimbusBranchesState(emptyList()))
|
||||
controller = NimbusBranchesController(nimbusBranchesStore, experiments, experimentId)
|
||||
controller = NimbusBranchesController(
|
||||
activity,
|
||||
navController,
|
||||
nimbusBranchesStore,
|
||||
experiments,
|
||||
experimentId
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN branch item is clicked THEN branch is opted into and selectedBranch state is updated`() {
|
||||
every { settings.isTelemetryEnabled } returns true
|
||||
every { settings.isExperimentationEnabled } returns true
|
||||
|
||||
val branch = Branch(
|
||||
slug = "slug",
|
||||
ratio = 1
|
||||
)
|
||||
|
||||
controller.onBranchItemClicked(branch)
|
||||
|
||||
nimbusBranchesStore.waitUntilIdle()
|
||||
|
||||
verify {
|
||||
experiments.optInWithBranch(experimentId, branch.slug)
|
||||
}
|
||||
|
||||
assertEquals(branch.slug, nimbusBranchesStore.state.selectedBranch)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN branch item is clicked THEN branch is opted out and selectedBranch state is updated`() {
|
||||
every { settings.isTelemetryEnabled } returns true
|
||||
every { settings.isExperimentationEnabled } returns true
|
||||
every { experiments.getExperimentBranch(experimentId) } returns "slug"
|
||||
|
||||
val branch = Branch(
|
||||
slug = "slug",
|
||||
ratio = 1
|
||||
)
|
||||
|
||||
controller.onBranchItemClicked(branch)
|
||||
|
||||
nimbusBranchesStore.waitUntilIdle()
|
||||
|
||||
verify {
|
||||
experiments.optOut(experimentId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN studies and telemetry are ON and item is clicked THEN branch is opted in`() {
|
||||
every { settings.isTelemetryEnabled } returns true
|
||||
every { settings.isExperimentationEnabled } returns true
|
||||
|
||||
val branch = Branch(
|
||||
slug = "slug",
|
||||
ratio = 1
|
||||
)
|
||||
|
||||
controller.onBranchItemClicked(branch)
|
||||
|
||||
nimbusBranchesStore.waitUntilIdle()
|
||||
|
||||
verify {
|
||||
experiments.optInWithBranch(experimentId, branch.slug)
|
||||
}
|
||||
|
||||
assertEquals(branch.slug, nimbusBranchesStore.state.selectedBranch)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN studies and telemetry are Off THEN branch is opted in AND data is not sent`() {
|
||||
every { settings.isTelemetryEnabled } returns false
|
||||
every { settings.isExperimentationEnabled } returns false
|
||||
every { activity.getString(any()) } returns "hello"
|
||||
|
||||
val branch = Branch(
|
||||
slug = "slug",
|
||||
ratio = 1
|
||||
)
|
||||
|
||||
controller.onBranchItemClicked(branch)
|
||||
|
||||
nimbusBranchesStore.waitUntilIdle()
|
||||
|
||||
verifyAll {
|
||||
experiments.getExperimentBranch(experimentId)
|
||||
experiments.optInWithBranch(experimentId, branch.slug)
|
||||
snackbar.setText("hello")
|
||||
}
|
||||
|
||||
assertEquals(branch.slug, nimbusBranchesStore.state.selectedBranch)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN studies are ON and telemetry Off THEN branch is opted in`() {
|
||||
every { settings.isExperimentationEnabled } returns true
|
||||
every { settings.isTelemetryEnabled } returns false
|
||||
|
||||
val branch = Branch(
|
||||
slug = "slug",
|
||||
ratio = 1
|
||||
)
|
||||
|
||||
controller.onBranchItemClicked(branch)
|
||||
|
||||
nimbusBranchesStore.waitUntilIdle()
|
||||
|
||||
verify {
|
||||
experiments.optInWithBranch(experimentId, branch.slug)
|
||||
}
|
||||
|
||||
assertEquals(branch.slug, nimbusBranchesStore.state.selectedBranch)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN studies are OFF and telemetry ON THEN branch is opted in`() {
|
||||
every { settings.isExperimentationEnabled } returns false
|
||||
every { settings.isTelemetryEnabled } returns true
|
||||
|
||||
val branch = Branch(
|
||||
slug = "slug",
|
||||
ratio = 1
|
||||
|
|
Loading…
Reference in New Issue