diff --git a/components/service/experiments/src/test/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivityTest.kt b/components/service/experiments/src/test/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivityTest.kt index 73674ca6099..f064ac7bbd6 100644 --- a/components/service/experiments/src/test/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivityTest.kt +++ b/components/service/experiments/src/test/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivityTest.kt @@ -12,12 +12,16 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.work.testing.WorkManagerTestInitHelper import kotlinx.coroutines.runBlocking +import mozilla.components.concept.fetch.Client +import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient import mozilla.components.service.experiments.Configuration import mozilla.components.service.experiments.Experiment import mozilla.components.service.experiments.Experiments import mozilla.components.service.experiments.ExperimentsSnapshot import mozilla.components.service.experiments.ExperimentsUpdater import mozilla.components.service.glean.Glean +import mozilla.components.service.glean.config.Configuration as GleanConfiguration +import mozilla.components.service.glean.net.ConceptFetchHttpUploader import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -42,7 +46,9 @@ class ExperimentsDebugActivityTest { fun setup() { WorkManagerTestInitHelper.initializeTestWorkManager(context) - Glean.initialize(context, uploadEnabled = true) + val httpClient = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client }) + val config = GleanConfiguration(httpClient = httpClient) + Glean.initialize(context, uploadEnabled = true, configuration = config) // This makes sure we have a "launch" intent in our package, otherwise // it will fail looking for it in `GleanDebugActivityTest`. diff --git a/components/service/glean/build.gradle b/components/service/glean/build.gradle index 147ee04c3f2..30f897e7937 100644 --- a/components/service/glean/build.gradle +++ b/components/service/glean/build.gradle @@ -50,10 +50,11 @@ dependencies { api GLEAN_LIBRARY + // So consumers can set a HTTP client. + api project(':concept-fetch') + implementation project(':support-ktx') implementation project(':support-base') - implementation project(':concept-fetch') - implementation project(':lib-fetch-httpurlconnection') implementation project(':support-utils') testImplementation Dependencies.androidx_test_core @@ -65,6 +66,7 @@ dependencies { testImplementation Dependencies.androidx_work_testing testImplementation project(':support-test') + testImplementation project(':lib-fetch-httpurlconnection') testImplementation project(':lib-fetch-okhttp') testImplementation GLEAN_LIBRARY_FORUNITTESTS diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt index 983b44354ef..477a486aefc 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt @@ -33,12 +33,11 @@ object Glean { * @param uploadEnabled A [Boolean] that determines the initial state of the uploader * @param configuration A Glean [Configuration] object with global settings. */ - @JvmOverloads @MainThread fun initialize( applicationContext: Context, uploadEnabled: Boolean, - configuration: Configuration = Configuration() + configuration: Configuration ) { GleanCore.initialize( applicationContext = applicationContext, diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt index 21a5fdc4805..5f632f03efd 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt @@ -4,26 +4,27 @@ package mozilla.components.service.glean.config -import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient -import mozilla.components.service.glean.net.ConceptFetchHttpUploader import mozilla.telemetry.glean.net.PingUploader import mozilla.telemetry.glean.config.Configuration as GleanCoreConfiguration /** * The Configuration class describes how to configure the Glean. * - * @property serverEndpoint the server pings are sent to. Please note that this is + * @property httpClient The HTTP client implementation to use for uploading pings. + * If you don't provide your own networking stack with an HTTP client to use, + * you can fall back to a simple implementation on top of `java.net` using + * `ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client })` + * @property serverEndpoint (optional) the server pings are sent to. Please note that this is * is only meant to be changed for tests. - * @property channel the release channel the application is on, if known. This will be + * @property channel (optional )the release channel the application is on, if known. This will be * sent along with all the pings, in the `client_info` section. - * @property maxEvents the number of events to store before the events ping is sent - * @property httpClient The HTTP client implementation to use for uploading pings. + * @property maxEvents (optional) the number of events to store before the events ping is sent */ data class Configuration @JvmOverloads constructor ( + val httpClient: PingUploader, val serverEndpoint: String = DEFAULT_TELEMETRY_ENDPOINT, val channel: String? = null, - val maxEvents: Int? = null, - val httpClient: PingUploader = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() }) + val maxEvents: Int? = null ) { // The following is required to support calling our API from Java. companion object { diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/net/ConceptFetchHttpUploader.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/net/ConceptFetchHttpUploader.kt index 01e119e5d66..f59c061ed1e 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/net/ConceptFetchHttpUploader.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/net/ConceptFetchHttpUploader.kt @@ -14,10 +14,12 @@ import mozilla.components.concept.fetch.isClientError import mozilla.components.concept.fetch.isSuccess import mozilla.components.support.base.log.logger.Logger import mozilla.telemetry.glean.net.HeadersList -import mozilla.telemetry.glean.net.PingUploader +import mozilla.telemetry.glean.net.PingUploader as CorePingUploader import java.io.IOException import java.util.concurrent.TimeUnit +typealias PingUploader = CorePingUploader + /** * A simple ping Uploader, which implements a "send once" policy, never * storing or attempting to send the ping again. This uses Android Component's @@ -33,6 +35,16 @@ class ConceptFetchHttpUploader( const val DEFAULT_CONNECTION_TIMEOUT = 10000L // The timeout, in milliseconds, to use when reading from the server. const val DEFAULT_READ_TIMEOUT = 30000L + + /** + * Export a constructor that is usable from Java. + * + * This looses the lazyness of creating the `client`. + */ + @JvmStatic + fun fromClient(client: Client): ConceptFetchHttpUploader { + return ConceptFetchHttpUploader(lazy { client }) + } } /** diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/GleanFromJavaTest.java b/components/service/glean/src/test/java/mozilla/components/service/glean/GleanFromJavaTest.java index e8d28ef0817..cfd3b2267f7 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/GleanFromJavaTest.java +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/GleanFromJavaTest.java @@ -16,7 +16,9 @@ import java.util.HashMap; import java.util.Map; +import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient; import mozilla.components.service.glean.config.Configuration; +import mozilla.components.service.glean.net.ConceptFetchHttpUploader; @RunWith(RobolectricTestRunner.class) public class GleanFromJavaTest { @@ -28,15 +30,18 @@ public class GleanFromJavaTest { public void testInitGleanWithDefaults() { Context context = ApplicationProvider.getApplicationContext(); WorkManagerTestInitHelper.initializeTestWorkManager(context); - Glean.INSTANCE.initialize(context, true); + ConceptFetchHttpUploader httpClient = ConceptFetchHttpUploader.fromClient(new HttpURLConnectionClient()); + Configuration config = new Configuration(httpClient); + Glean.INSTANCE.initialize(context, true, config); } @Test public void testInitGleanWithConfiguration() { Context context = ApplicationProvider.getApplicationContext(); WorkManagerTestInitHelper.initializeTestWorkManager(context); + ConceptFetchHttpUploader httpClient = ConceptFetchHttpUploader.fromClient(new HttpURLConnectionClient()); Configuration config = - new Configuration(Configuration.DEFAULT_TELEMETRY_ENDPOINT, "test-channel"); + new Configuration(httpClient, Configuration.DEFAULT_TELEMETRY_ENDPOINT, "test-channel"); Glean.INSTANCE.initialize(context, true, config); } diff --git a/docs/changelog.md b/docs/changelog.md index e2fde240327..de2d38d720d 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -12,6 +12,13 @@ permalink: /changelog/ * [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt) * [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt) +* **service-glean** + * ⚠️ **This is a breaking change**: Glean's configuration now requires explicitly setting an http client. Users need to pass one at construction. + A default `lib-fetch-httpurlconnection` implementation is available. + Add it to the configuration object like this: + `val config = Configuration(httpClient = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client }))`. + See [PR #6875](https://github.com/mozilla-mobile/android-components/pull/6875) for details and full code examples. + # 41.0.0 * [Commits](https://github.com/mozilla-mobile/android-components/compare/v40.0.0...v41.0.0) diff --git a/samples/browser/src/main/java/org/mozilla/samples/browser/SampleApplication.kt b/samples/browser/src/main/java/org/mozilla/samples/browser/SampleApplication.kt index 39398ca20f1..d33a1660e00 100644 --- a/samples/browser/src/main/java/org/mozilla/samples/browser/SampleApplication.kt +++ b/samples/browser/src/main/java/org/mozilla/samples/browser/SampleApplication.kt @@ -6,8 +6,12 @@ package org.mozilla.samples.browser import android.app.Application import mozilla.components.browser.session.Session +import mozilla.components.concept.fetch.Client import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider +import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient import mozilla.components.service.glean.Glean +import mozilla.components.service.glean.config.Configuration +import mozilla.components.service.glean.net.ConceptFetchHttpUploader import mozilla.components.support.base.facts.Facts import mozilla.components.support.base.facts.processor.LogFactProcessor import mozilla.components.support.base.log.Log @@ -31,10 +35,12 @@ class SampleApplication : Application() { return } + val httpClient = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client }) + val config = Configuration(httpClient = httpClient) // IMPORTANT: the following lines initialize the Glean SDK but disable upload // of pings. If, for testing purposes, upload is required to be on, change the // next line to `uploadEnabled = true`. - Glean.initialize(applicationContext, uploadEnabled = false) + Glean.initialize(applicationContext, uploadEnabled = false, configuration = config) Facts.registerProcessor(LogFactProcessor()) diff --git a/samples/crash/build.gradle b/samples/crash/build.gradle index 6d0da0f2a41..f97a54ee831 100644 --- a/samples/crash/build.gradle +++ b/samples/crash/build.gradle @@ -30,6 +30,7 @@ android { dependencies { implementation project(':lib-crash') + implementation project(':lib-fetch-httpurlconnection') implementation project(':service-glean') implementation project(':support-base') diff --git a/samples/crash/src/main/java/org/mozilla/samples/crash/CrashApplication.kt b/samples/crash/src/main/java/org/mozilla/samples/crash/CrashApplication.kt index a1f8d6ac993..e72ac62ca56 100644 --- a/samples/crash/src/main/java/org/mozilla/samples/crash/CrashApplication.kt +++ b/samples/crash/src/main/java/org/mozilla/samples/crash/CrashApplication.kt @@ -14,12 +14,16 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import mozilla.components.support.base.log.Log import mozilla.components.support.base.log.sink.AndroidLogSink +import mozilla.components.concept.fetch.Client import mozilla.components.lib.crash.Crash import mozilla.components.lib.crash.CrashReporter import mozilla.components.lib.crash.service.CrashReporterService import mozilla.components.lib.crash.service.GleanCrashReporterService +import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient import mozilla.components.service.glean.Glean import mozilla.components.support.base.crash.Breadcrumb +import mozilla.components.service.glean.config.Configuration +import mozilla.components.service.glean.net.ConceptFetchHttpUploader import java.util.UUID class CrashApplication : Application() { @@ -49,7 +53,9 @@ class CrashApplication : Application() { ).install(this) // Initialize Glean for recording by the GleanCrashReporterService - Glean.initialize(applicationContext, uploadEnabled = true) + val httpClient = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client }) + val config = Configuration(httpClient = httpClient) + Glean.initialize(applicationContext, uploadEnabled = true, configuration = config) } companion object { diff --git a/samples/glean/build.gradle b/samples/glean/build.gradle index 67bd9d26e5d..beaaa54e066 100644 --- a/samples/glean/build.gradle +++ b/samples/glean/build.gradle @@ -50,6 +50,7 @@ dependencies { implementation project(':service-glean') implementation project(':service-experiments') implementation project(':support-base') + implementation project(':lib-fetch-httpurlconnection') implementation Dependencies.kotlin_stdlib implementation Dependencies.kotlin_coroutines diff --git a/samples/glean/src/main/java/org/mozilla/samples/glean/GleanApplication.kt b/samples/glean/src/main/java/org/mozilla/samples/glean/GleanApplication.kt index 05648e46320..9c3e1717c14 100644 --- a/samples/glean/src/main/java/org/mozilla/samples/glean/GleanApplication.kt +++ b/samples/glean/src/main/java/org/mozilla/samples/glean/GleanApplication.kt @@ -6,7 +6,11 @@ package org.mozilla.samples.glean import android.app.Application import android.content.Intent +import mozilla.components.concept.fetch.Client +import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient import mozilla.components.service.glean.Glean +import mozilla.components.service.glean.config.Configuration +import mozilla.components.service.glean.net.ConceptFetchHttpUploader import mozilla.components.service.experiments.Experiments import mozilla.components.support.base.log.Log import mozilla.components.support.base.log.sink.AndroidLogSink @@ -28,7 +32,9 @@ class GleanApplication : Application() { // Initialize the Glean library. Ideally, this is the first thing that // must be done right after enabling logging. - Glean.initialize(applicationContext, uploadEnabled = true) + val httpClient = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client }) + val config = Configuration(httpClient = httpClient) + Glean.initialize(applicationContext, uploadEnabled = true, configuration = config) // Initialize the Experiments library and pass in the callback that will generate a // broadcast Intent to signal the application that experiments have been updated. This is