|
|
@ -10,7 +10,9 @@ import androidx.appcompat.app.AppCompatDelegate
|
|
|
|
import androidx.preference.PreferenceManager
|
|
|
|
import androidx.preference.PreferenceManager
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.GlobalScope
|
|
|
|
import kotlinx.coroutines.GlobalScope
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.async
|
|
|
|
|
|
|
|
import kotlinx.coroutines.runBlocking
|
|
|
|
|
|
|
|
import kotlinx.coroutines.Deferred
|
|
|
|
import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
|
|
|
|
import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
|
|
|
|
import mozilla.components.service.fretboard.Fretboard
|
|
|
|
import mozilla.components.service.fretboard.Fretboard
|
|
|
|
import mozilla.components.service.fretboard.source.kinto.KintoExperimentSource
|
|
|
|
import mozilla.components.service.fretboard.source.kinto.KintoExperimentSource
|
|
|
@ -28,11 +30,18 @@ import java.io.File
|
|
|
|
@SuppressLint("Registered")
|
|
|
|
@SuppressLint("Registered")
|
|
|
|
open class FenixApplication : Application() {
|
|
|
|
open class FenixApplication : Application() {
|
|
|
|
lateinit var fretboard: Fretboard
|
|
|
|
lateinit var fretboard: Fretboard
|
|
|
|
|
|
|
|
lateinit var experimentLoader: Deferred<Boolean>
|
|
|
|
|
|
|
|
var experimentLoaderComplete: Boolean = false
|
|
|
|
|
|
|
|
|
|
|
|
val components by lazy { Components(this) }
|
|
|
|
val components by lazy { Components(this) }
|
|
|
|
|
|
|
|
|
|
|
|
override fun onCreate() {
|
|
|
|
override fun onCreate() {
|
|
|
|
super.onCreate()
|
|
|
|
super.onCreate()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// loadExperiments does things that run in parallel with the rest of setup.
|
|
|
|
|
|
|
|
// Call the function as early as possible so there's maximum overlap.
|
|
|
|
|
|
|
|
experimentLoader = loadExperiments()
|
|
|
|
|
|
|
|
|
|
|
|
setDayNightTheme()
|
|
|
|
setDayNightTheme()
|
|
|
|
val megazordEnabled = setupMegazord()
|
|
|
|
val megazordEnabled = setupMegazord()
|
|
|
|
setupLogging(megazordEnabled)
|
|
|
|
setupLogging(megazordEnabled)
|
|
|
@ -47,12 +56,42 @@ open class FenixApplication : Application() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setupLeakCanary()
|
|
|
|
setupLeakCanary()
|
|
|
|
loadExperiments()
|
|
|
|
|
|
|
|
if (Settings.getInstance(this).isTelemetryEnabled) {
|
|
|
|
if (Settings.getInstance(this).isTelemetryEnabled) {
|
|
|
|
components.analytics.metrics.start()
|
|
|
|
components.analytics.metrics.start()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Wait until all experiments are loaded
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* This function will cause the caller to block until the experiments are loaded.
|
|
|
|
|
|
|
|
* It could be used in any number of reasons, but the most likely scenario is that
|
|
|
|
|
|
|
|
* a calling function needs to access the loaded experiments and wants to
|
|
|
|
|
|
|
|
* make sure that the experiments are loaded from the server before doing so.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Because this function is synchronized, it can only be accessed by one thread
|
|
|
|
|
|
|
|
* at a time. Anyone trying to check the loaded status will wait if someone is
|
|
|
|
|
|
|
|
* already waiting. This is okay because the thread waiting for access to the
|
|
|
|
|
|
|
|
* function will immediately see that the loader is complete upon gaining the
|
|
|
|
|
|
|
|
* opportunity to run the function.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Synchronized
|
|
|
|
|
|
|
|
public fun waitForExperimentsToLoad() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Do we know that we are already complete?
|
|
|
|
|
|
|
|
if (!experimentLoaderComplete) {
|
|
|
|
|
|
|
|
// No? Have we completed since the last call?
|
|
|
|
|
|
|
|
if (!experimentLoader.isCompleted) {
|
|
|
|
|
|
|
|
// No? Well, let's wait.
|
|
|
|
|
|
|
|
runBlocking {
|
|
|
|
|
|
|
|
experimentLoader.await()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set this so we don't have to wait on the next call.
|
|
|
|
|
|
|
|
experimentLoaderComplete = true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected open fun setupLeakCanary() {
|
|
|
|
protected open fun setupLeakCanary() {
|
|
|
|
// no-op, LeakCanary is disabled by default
|
|
|
|
// no-op, LeakCanary is disabled by default
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -73,22 +112,23 @@ open class FenixApplication : Application() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun loadExperiments() {
|
|
|
|
private fun loadExperiments(): Deferred<Boolean> {
|
|
|
|
val experimentsFile = File(filesDir, EXPERIMENTS_JSON_FILENAME)
|
|
|
|
return GlobalScope.async(Dispatchers.IO) {
|
|
|
|
val experimentSource = KintoExperimentSource(
|
|
|
|
val experimentsFile = File(filesDir, EXPERIMENTS_JSON_FILENAME)
|
|
|
|
EXPERIMENTS_BASE_URL,
|
|
|
|
val experimentSource = KintoExperimentSource(
|
|
|
|
EXPERIMENTS_BUCKET_NAME,
|
|
|
|
EXPERIMENTS_BASE_URL,
|
|
|
|
EXPERIMENTS_COLLECTION_NAME,
|
|
|
|
EXPERIMENTS_BUCKET_NAME,
|
|
|
|
// TODO Switch back to components.core.client (see https://github.com/mozilla-mobile/fenix/issues/1329)
|
|
|
|
EXPERIMENTS_COLLECTION_NAME,
|
|
|
|
HttpURLConnectionClient()
|
|
|
|
// TODO Switch back to components.core.client (see https://github.com/mozilla-mobile/fenix/issues/1329)
|
|
|
|
)
|
|
|
|
HttpURLConnectionClient()
|
|
|
|
// TODO add ValueProvider to keep clientID in sync with Glean when ready
|
|
|
|
)
|
|
|
|
fretboard = Fretboard(experimentSource, FlatFileExperimentStorage(experimentsFile))
|
|
|
|
// TODO add ValueProvider to keep clientID in sync with Glean when ready
|
|
|
|
fretboard.loadExperiments()
|
|
|
|
fretboard = Fretboard(experimentSource, FlatFileExperimentStorage(experimentsFile))
|
|
|
|
Logger.debug("Bucket is ${fretboard.getUserBucket(this@FenixApplication)}")
|
|
|
|
fretboard.loadExperiments()
|
|
|
|
Logger.debug("Experiments active: ${fretboard.getExperimentsMap(this@FenixApplication)}")
|
|
|
|
Logger.debug("Bucket is ${fretboard.getUserBucket(this@FenixApplication)}")
|
|
|
|
GlobalScope.launch(Dispatchers.IO) {
|
|
|
|
Logger.debug("Experiments active: ${fretboard.getExperimentsMap(this@FenixApplication)}")
|
|
|
|
fretboard.updateExperiments()
|
|
|
|
fretboard.updateExperiments()
|
|
|
|
|
|
|
|
return@async true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|