From 42f58a19847a75e91bcabbf6a3c1095b165dddb1 Mon Sep 17 00:00:00 2001 From: Sawyer Blatz Date: Thu, 28 May 2020 09:37:45 -0700 Subject: [PATCH] For #9488: Add experimentation support --- app/build.gradle | 1 + .../org/mozilla/fenix/ExperimentsManager.kt | 39 +++++++++++++++++++ .../org/mozilla/fenix/FenixApplication.kt | 28 ++++++++++++- .../org/mozilla/fenix/cfr/SearchWidgetCFR.kt | 4 +- .../fenix/components/SearchWidgetCreator.kt | 6 +-- .../java/org/mozilla/fenix/utils/Settings.kt | 12 ++++++ app/src/main/res/values/preference_keys.xml | 1 + buildSrc/src/main/java/Dependencies.kt | 2 + 8 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/ExperimentsManager.kt diff --git a/app/build.gradle b/app/build.gradle index ee41a6678..76b93b6e4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -501,6 +501,7 @@ dependencies { implementation Deps.mozilla_feature_webcompat implementation Deps.mozilla_feature_webnotifications + implementation Deps.mozilla_service_experiments implementation Deps.mozilla_service_sync_logins implementation Deps.mozilla_service_firefox_accounts implementation Deps.mozilla_service_glean diff --git a/app/src/main/java/org/mozilla/fenix/ExperimentsManager.kt b/app/src/main/java/org/mozilla/fenix/ExperimentsManager.kt new file mode 100644 index 000000000..d93b77bad --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/ExperimentsManager.kt @@ -0,0 +1,39 @@ +/* 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 + +import android.content.Context +import mozilla.components.service.experiments.Experiments +import org.mozilla.fenix.ext.settings + +object ExperimentsManager { + + fun optOutSearchWidgetExperiment(context: Context) { + // Release user has opted out of search widget CFR experiment, reset them to not see it. + context.settings().setSearchWidgetExperiment(false) + } + + fun initSearchWidgetExperiment(context: Context) { + // When the `search-widget-discoverability` experiment is active,set the pref to either + // show or hide the search widget CFR (given other criteria are met as well). + // Note that this will not take effect the first time the application has launched, + // since there won't be enough time for the experiments library to get a list of experiments. + // It will take effect the second time the application is launched. + Experiments.withExperiment("fenix-search-widget") { branchName -> + when (branchName) { + "control_no_cfr" -> { + context.settings().setSearchWidgetExperiment(false) + } + "treatment_cfr" -> { + context.settings().setSearchWidgetExperiment(true) + } + else -> { + // No branch matches so we're defaulting to no CFR + context.settings().setSearchWidgetExperiment(false) + } + } + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index 411692612..7e1e24d51 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -23,6 +23,7 @@ import mozilla.components.browser.session.Session import mozilla.components.concept.push.PushProcessor import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider import mozilla.components.lib.crash.CrashReporter +import mozilla.components.service.experiments.Experiments import mozilla.components.service.glean.Glean import mozilla.components.service.glean.config.Configuration import mozilla.components.service.glean.net.ConceptFetchHttpUploader @@ -162,10 +163,31 @@ open class FenixApplication : LocaleAwareApplication() { // runStorageMaintenance() // } + val taskQueue = components.performance.visualCompletenessQueue registerActivityLifecycleCallbacks( - PerformanceActivityLifecycleCallbacks(components.performance.visualCompletenessQueue) + PerformanceActivityLifecycleCallbacks(taskQueue) ) + // Enable the service-experiments component to be initialized after visual completeness + // for performance wins. + if (settings().isExperimentationEnabled && Config.channel.isReleaseOrBeta) { + taskQueue.runIfReadyOrQueue { + Experiments.initialize( + applicationContext = applicationContext, + configuration = mozilla.components.service.experiments.Configuration( + httpClient = components.core.client, + kintoEndpoint = KINTO_ENDPOINT_PROD + ) + ) + } + } else { + // We should make a better way to opt out for when we have more experiments + // See https://github.com/mozilla-mobile/fenix/issues/6278 + ExperimentsManager.optOutSearchWidgetExperiment(this) + } + + ExperimentsManager.initSearchWidgetExperiment(this) + components.performance.visualCompletenessQueue.runIfReadyOrQueue { GlobalScope.launch(Dispatchers.IO) { logger.info("Running post-visual completeness tasks...") @@ -394,4 +416,8 @@ open class FenixApplication : LocaleAwareApplication() { applicationContext.resources.configuration.uiMode = config.uiMode super.onConfigurationChanged(config) } + + companion object { + private const val KINTO_ENDPOINT_PROD = "https://firefox.settings.services.mozilla.com/v1" + } } diff --git a/app/src/main/java/org/mozilla/fenix/cfr/SearchWidgetCFR.kt b/app/src/main/java/org/mozilla/fenix/cfr/SearchWidgetCFR.kt index 00f0c084f..41827caba 100644 --- a/app/src/main/java/org/mozilla/fenix/cfr/SearchWidgetCFR.kt +++ b/app/src/main/java/org/mozilla/fenix/cfr/SearchWidgetCFR.kt @@ -17,7 +17,6 @@ import androidx.core.view.marginTop import kotlinx.android.synthetic.main.search_widget_cfr.view.* import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.drop_down_triangle import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.pop_up_triangle -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.components.SearchWidgetCreator import org.mozilla.fenix.components.metrics.Event @@ -34,7 +33,8 @@ class SearchWidgetCFR( ) { fun displayIfNecessary() { - if (!context.settings().shouldDisplaySearchWidgetCFR() || !FeatureFlags.searchWidgetCFR) { return } + if (!context.settings().isInSearchWidgetExperiment || + !context.settings().shouldDisplaySearchWidgetCFR()) { return } showSearchWidgetCFR() } diff --git a/app/src/main/java/org/mozilla/fenix/components/SearchWidgetCreator.kt b/app/src/main/java/org/mozilla/fenix/components/SearchWidgetCreator.kt index 41734d754..5e50a961c 100644 --- a/app/src/main/java/org/mozilla/fenix/components/SearchWidgetCreator.kt +++ b/app/src/main/java/org/mozilla/fenix/components/SearchWidgetCreator.kt @@ -23,11 +23,7 @@ object SearchWidgetCreator { @TargetApi(Build.VERSION_CODES.O) fun createSearchWidget(context: Context): Boolean { val appWidgetManager: AppWidgetManager = context.getSystemService(AppWidgetManager::class.java) - if (!appWidgetManager.isRequestPinAppWidgetSupported) { return false } - val myProvider = ComponentName(context, SearchWidgetProvider::class.java) - appWidgetManager.requestPinAppWidget(myProvider, null, null) - - return true + return appWidgetManager.requestPinAppWidget(myProvider, null, null) } } diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index ee8c4365c..dd37b672f 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -208,6 +208,18 @@ class Settings private constructor( ).apply() } + val isInSearchWidgetExperiment by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_is_in_search_widget_experiment), + default = false + ) + + fun setSearchWidgetExperiment(value: Boolean) { + preferences.edit().putBoolean( + appContext.getPreferenceKey(R.string.pref_key_is_in_search_widget_experiment), + value + ).apply() + } + var defaultSearchEngineName by stringPreference( appContext.getPreferenceKey(R.string.pref_key_search_engine), default = "" diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 1f56530dc..6fff977aa 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -177,5 +177,6 @@ pref_key_search_widget_cfr_display_count pref_key_search_widget_cfr_dismiss_count pref_key_search_widget_cfr_manually_dismissed + pref_key_is_in_search_widget_experiment pref_key_show_search_widget_cfr diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 11e1a307e..f41d6f139 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -115,6 +115,8 @@ object Deps { const val mozilla_feature_webcompat = "org.mozilla.components:feature-webcompat:${Versions.mozilla_android_components}" const val mozilla_feature_webnotifications = "org.mozilla.components:feature-webnotifications:${Versions.mozilla_android_components}" + const val mozilla_service_experiments = + "org.mozilla.components:service-experiments:${Versions.mozilla_android_components}" const val mozilla_service_sync_logins = "org.mozilla.components:service-sync-logins:${Versions.mozilla_android_components}" const val mozilla_service_firefox_accounts = "org.mozilla.components:service-firefox-accounts:${Versions.mozilla_android_components}"