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}"