[fenix] For https://github.com/mozilla-mobile/fenix/issues/23503: Respect studies and telemetry prefs when manually opting in to studies (https://github.com/mozilla-mobile/fenix/pull/23955)

* For https://github.com/mozilla-mobile/fenix/issues/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>
pull/600/head
Elise Richards 2 years ago committed by GitHub
parent 76b3b8a926
commit c181d526d0

@ -10,6 +10,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -47,6 +48,8 @@ class NimbusBranchesFragment : Fragment() {
} }
controller = NimbusBranchesController( controller = NimbusBranchesController(
context = requireContext(),
navController = findNavController(),
nimbusBranchesStore = nimbusBranchesStore, nimbusBranchesStore = nimbusBranchesStore,
experiments = requireContext().components.analytics.experiments, experiments = requireContext().components.analytics.experiments,
experimentId = args.experimentId experimentId = args.experimentId

@ -4,15 +4,22 @@
package org.mozilla.fenix.nimbus.controller 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.NimbusApi
import mozilla.components.service.nimbus.ui.NimbusBranchesAdapterDelegate import mozilla.components.service.nimbus.ui.NimbusBranchesAdapterDelegate
import org.mozilla.experiments.nimbus.Branch 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.NimbusBranchesAction
import org.mozilla.fenix.nimbus.NimbusBranchesFragmentDirections
import org.mozilla.fenix.nimbus.NimbusBranchesStore import org.mozilla.fenix.nimbus.NimbusBranchesStore
/** /**
* [NimbusBranchesFragment] controller. This implements [NimbusBranchesAdapterDelegate] to handle * [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 * @param nimbusBranchesStore An instance of [NimbusBranchesStore] for dispatching
* [NimbusBranchesAction]s. * [NimbusBranchesAction]s.
@ -20,12 +27,41 @@ import org.mozilla.fenix.nimbus.NimbusBranchesStore
* @param experimentId The string experiment-id or "slug" for a Nimbus experiment. * @param experimentId The string experiment-id or "slug" for a Nimbus experiment.
*/ */
class NimbusBranchesController( class NimbusBranchesController(
private val context: Context,
private val navController: NavController,
private val nimbusBranchesStore: NimbusBranchesStore, private val nimbusBranchesStore: NimbusBranchesStore,
private val experiments: NimbusApi, private val experiments: NimbusApi,
private val experimentId: String private val experimentId: String
) : NimbusBranchesAdapterDelegate { ) : NimbusBranchesAdapterDelegate {
override fun onBranchItemClicked(branch: Branch) { 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( nimbusBranchesStore.dispatch(
if (experiments.getExperimentBranch(experimentId) != branch.slug) { if (experiments.getExperimentBranch(experimentId) != branch.slug) {
experiments.optInWithBranch(experimentId, branch.slug) experiments.optInWithBranch(experimentId, branch.slug)

@ -1160,6 +1160,14 @@
<argument <argument
android:name="experimentName" android:name="experimentName"
app:argType="string" /> 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> </fragment>
</navigation> </navigation>

@ -1763,4 +1763,9 @@
<string name="pocket_stories_feature_caption">Part of the Firefox family. %s</string> <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. --> <!-- Clickable text for opening an external link for more information about Pocket. -->
<string name="pocket_stories_feature_learn_more">Learn more</string> <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> </resources>

@ -4,32 +4,196 @@
package org.mozilla.fenix.nimbus 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.mockk
import io.mockk.mockkObject
import io.mockk.verify import io.mockk.verify
import io.mockk.verifyAll
import mozilla.components.service.nimbus.NimbusApi import mozilla.components.service.nimbus.NimbusApi
import mozilla.components.support.test.libstate.ext.waitUntilIdle import mozilla.components.support.test.libstate.ext.waitUntilIdle
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.experiments.nimbus.Branch 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.nimbus.controller.NimbusBranchesController
import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class NimbusBranchesControllerTest { class NimbusBranchesControllerTest {
private val experiments: NimbusApi = mockk(relaxed = true) private val experiments: NimbusApi = mockk(relaxed = true)
private val experimentId = "id" private val experimentId = "id"
private lateinit var controller: NimbusBranchesController private lateinit var controller: NimbusBranchesController
private lateinit var navController: NavController
private lateinit var nimbusBranchesStore: NimbusBranchesStore 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 @Before
fun setup() { 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())) nimbusBranchesStore = NimbusBranchesStore(NimbusBranchesState(emptyList()))
controller = NimbusBranchesController(nimbusBranchesStore, experiments, experimentId) controller = NimbusBranchesController(
activity,
navController,
nimbusBranchesStore,
experiments,
experimentId
)
} }
@Test @Test
fun `WHEN branch item is clicked THEN branch is opted into and selectedBranch state is updated`() { 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( val branch = Branch(
slug = "slug", slug = "slug",
ratio = 1 ratio = 1

Loading…
Cancel
Save