From 88143495dbb2d71cddfdc8cfaa8003bb13322e21 Mon Sep 17 00:00:00 2001 From: Travis Long Date: Thu, 8 Aug 2019 13:33:42 -0500 Subject: [PATCH 01/38] Bug 1572509 - Fix PingUploadWorker loop if upload disabled --- .../glean/scheduler/PingUploadWorker.kt | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt index be55855d6ee..fdfdfcce37e 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt @@ -43,7 +43,7 @@ class PingUploadWorker(context: Context, params: WorkerParameters) : Worker(cont * @return [OneTimeWorkRequest] representing the task for the [WorkManager] to enqueue and run */ internal fun buildWorkRequest(): OneTimeWorkRequest = OneTimeWorkRequestBuilder() - .addTag(PingUploadWorker.PING_WORKER_TAG) + .addTag(PING_WORKER_TAG) .setConstraints(buildConstraints()) .build() @@ -52,9 +52,9 @@ class PingUploadWorker(context: Context, params: WorkerParameters) : Worker(cont */ internal fun enqueueWorker() { WorkManager.getInstance().enqueueUniqueWork( - PingUploadWorker.PING_WORKER_TAG, + PING_WORKER_TAG, ExistingWorkPolicy.KEEP, - PingUploadWorker.buildWorkRequest()) + buildWorkRequest()) } /** @@ -63,12 +63,9 @@ class PingUploadWorker(context: Context, params: WorkerParameters) : Worker(cont * * @return true if process was successful */ - internal fun uploadPings(): Boolean { - if (Glean.getUploadEnabled()) { - val httpPingUploader = HttpPingUploader() - return Glean.pingStorageEngine.process(httpPingUploader::upload) - } - return false + private fun uploadPings(): Boolean { + val httpPingUploader = HttpPingUploader() + return Glean.pingStorageEngine.process(httpPingUploader::upload) } } @@ -85,10 +82,10 @@ class PingUploadWorker(context: Context, params: WorkerParameters) : Worker(cont * @return The [androidx.work.ListenableWorker.Result] of the computation */ override fun doWork(): Result { - if (!uploadPings()) { - return Result.retry() + return when { + !Glean.getUploadEnabled() -> Result.failure() + !uploadPings() -> Result.retry() + else -> Result.success() } - - return Result.success() } } From 6835a19f3f5625c46cf3b95f9a5eb8f12167c82a Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Fri, 2 Aug 2019 10:31:16 -0400 Subject: [PATCH 02/38] Closes #3769: Add SendTabFeature with push support --- .../feature/push/AutoPushFeature.kt | 10 ++ components/feature/sendtab/build.gradle | 3 + .../feature/sendtab/SendTabFeature.kt | 140 ++++++++++++++++++ .../feature/sendtab/AccountObserverTest.kt | 72 +++++++++ .../feature/sendtab/DeviceObserverTest.kt | 49 ++++++ .../feature/sendtab/PushObserverTest.kt | 90 +++++++++++ .../feature/sendtab/SendTabFeatureKtTest.kt | 78 ++++++++++ .../feature/sendtab/SendTabUseCasesTest.kt | 26 ++-- 8 files changed, 454 insertions(+), 14 deletions(-) create mode 100644 components/feature/sendtab/src/main/java/mozilla/components/feature/sendtab/SendTabFeature.kt create mode 100644 components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/AccountObserverTest.kt create mode 100644 components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/DeviceObserverTest.kt create mode 100644 components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/PushObserverTest.kt create mode 100644 components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabFeatureKtTest.kt diff --git a/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt b/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt index 212fa5fc11e..864d5b12af2 100644 --- a/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt +++ b/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt @@ -205,6 +205,11 @@ class AutoPushFeature( /** * Returns subscription information for the push type if available. + * + * Implementation notes: We need to connect this to the device constellation so that we update our subscriptions + * when notified by FxA. See [#3859][0]. + * + * [0]: https://github.com/mozilla-mobile/android-components/issues/3859 */ fun unsubscribeForType(type: PushType) { DeliveryManager.with(connection) { @@ -231,6 +236,11 @@ class AutoPushFeature( /** * Deletes the registration token locally so that it forces the service to get a new one the * next time hits it's messaging server. + * + * Implementation notes: This shouldn't need to be used unless we're certain. When we introduce + * [a polling service][0] to check if endpoints are expired, we would invoke this. + * + * [0]: https://github.com/mozilla-mobile/android-components/issues/3173 */ fun forceRegistrationRenewal() { // Remove the cached token we have. diff --git a/components/feature/sendtab/build.gradle b/components/feature/sendtab/build.gradle index d3d088bf3c5..d3d31ff59a9 100644 --- a/components/feature/sendtab/build.gradle +++ b/components/feature/sendtab/build.gradle @@ -31,7 +31,10 @@ dependencies { implementation project(':service-firefox-accounts') implementation project(':support-ktx') implementation project(':support-base') + implementation project(':concept-push') + implementation project(':feature-push') + implementation Dependencies.androidx_work_runtime implementation Dependencies.kotlin_stdlib implementation Dependencies.kotlin_coroutines diff --git a/components/feature/sendtab/src/main/java/mozilla/components/feature/sendtab/SendTabFeature.kt b/components/feature/sendtab/src/main/java/mozilla/components/feature/sendtab/SendTabFeature.kt new file mode 100644 index 00000000000..8b4541e2b32 --- /dev/null +++ b/components/feature/sendtab/src/main/java/mozilla/components/feature/sendtab/SendTabFeature.kt @@ -0,0 +1,140 @@ +/* + * 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 mozilla.components.feature.sendtab + +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ProcessLifecycleOwner +import mozilla.components.concept.push.Bus +import mozilla.components.concept.push.PushService +import mozilla.components.concept.sync.AccountObserver as SyncAccountObserver +import mozilla.components.concept.sync.Device +import mozilla.components.concept.sync.DeviceConstellation +import mozilla.components.concept.sync.DeviceEvent +import mozilla.components.concept.sync.DeviceEventsObserver +import mozilla.components.concept.sync.DevicePushSubscription +import mozilla.components.concept.sync.OAuthAccount +import mozilla.components.concept.sync.TabData +import mozilla.components.feature.push.AutoPushFeature +import mozilla.components.feature.push.AutoPushSubscription +import mozilla.components.feature.push.PushSubscriptionObserver +import mozilla.components.feature.push.PushType +import mozilla.components.service.fxa.manager.FxaAccountManager +import mozilla.components.support.base.log.logger.Logger + +/** + * A feature that uses the [FxaAccountManager] to send and receive tabs with optional push support + * for receiving tabs from the [AutoPushFeature] and a [PushService]. + * + * If the push components are not used, the feature can still function while tabs would only be + * received when refreshing the device state. + * + * @param accountManager Firefox account manager. + * @param pushFeature The [AutoPushFeature] if that is setup for observing push events. + * @param owner Android lifecycle owner for the observers. Defaults to the [ProcessLifecycleOwner] + * so that we can always observe events throughout the application lifecycle. + * @param autoPause whether or not the observer should automatically be + * paused/resumed with the bound lifecycle. + * @param onTabsReceived the callback invoked with new tab(s) are received. + */ +class SendTabFeature( + accountManager: FxaAccountManager, + pushFeature: AutoPushFeature? = null, + owner: LifecycleOwner = ProcessLifecycleOwner.get(), + autoPause: Boolean = false, + onTabsReceived: (Device?, List) -> Unit +) { + init { + val accountObserver = AccountObserver(pushFeature) + val pushObserver = PushObserver(accountManager) + val deviceObserver = DeviceObserver(onTabsReceived) + + // Always observe the account for device events. + accountManager.registerForDeviceEvents(deviceObserver, owner, autoPause) + + pushFeature?.apply { + registerForPushMessages(PushType.Services, pushObserver, owner, autoPause) + registerForSubscriptions(pushObserver, owner, autoPause) + + // observe the account only if we have the push feature (service is optional) + accountManager.register(accountObserver, owner, autoPause) + } + } +} + +internal class PushObserver( + private val accountManager: FxaAccountManager +) : Bus.Observer, PushSubscriptionObserver { + private val logger = Logger("PushObserver") + + override fun onSubscriptionAvailable(subscription: AutoPushSubscription) { + logger.debug("Received new push subscription from $subscription.type") + + if (subscription.type == PushType.Services) { + accountManager.withConstellation { + it.setDevicePushSubscriptionAsync( + DevicePushSubscription( + endpoint = subscription.endpoint, + publicKey = subscription.publicKey, + authKey = subscription.authKey + ) + ) + } + } + } + + override fun onEvent(type: PushType, message: String) { + logger.debug("Received new push message for $type") + + accountManager.withConstellation { + it.processRawEventAsync(message) + } + } +} + +internal class DeviceObserver( + private val onTabsReceived: (Device?, List) -> Unit +) : DeviceEventsObserver { + private val logger = Logger("DeviceObserver") + + override fun onEvents(events: List) { + events.asSequence() + .filterIsInstance() + .forEach { event -> + logger.debug("Showing ${event.entries.size} tab(s) received from deviceID=${event.from?.id}") + + onTabsReceived(event.from, event.entries) + } + } +} + +internal class AccountObserver( + private val feature: AutoPushFeature? +) : SyncAccountObserver { + private val logger = Logger("AccountObserver") + + override fun onAuthenticated(account: OAuthAccount, newAccount: Boolean) { + // We need a new subscription only when we have a new account. + // This is removed when an account logs out. + if (newAccount) { + logger.debug("Subscribing for ${PushType.Services} events.") + + feature?.subscribeForType(PushType.Services) + } + } + + override fun onLoggedOut() { + logger.debug("Unsubscribing for ${PushType.Services} events.") + + feature?.unsubscribeForType(PushType.Services) + } +} + +internal inline fun FxaAccountManager.withConstellation(block: (DeviceConstellation) -> Unit) { + authenticatedAccount()?.let { + block(it.deviceConstellation()) + } +} diff --git a/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/AccountObserverTest.kt b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/AccountObserverTest.kt new file mode 100644 index 00000000000..f92c9107291 --- /dev/null +++ b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/AccountObserverTest.kt @@ -0,0 +1,72 @@ +/* + * 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 mozilla.components.feature.sendtab + +import mozilla.components.feature.push.AutoPushFeature +import mozilla.components.feature.push.PushType +import mozilla.components.support.test.mock +import org.junit.Test +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions + +class AccountObserverTest { + @Test + fun `feature and service invoked on new account authenticated`() { + val feature: AutoPushFeature = mock() + val observer = AccountObserver(feature) + + observer.onAuthenticated(mock(), true) + + verify(feature).subscribeForType(PushType.Services) + + verifyNoMoreInteractions(feature) + } + + @Test + fun `feature and service are not invoked if not provided`() { + val feature: AutoPushFeature = mock() + val observer = AccountObserver(null) + + observer.onAuthenticated(mock(), true) + observer.onLoggedOut() + + verifyNoMoreInteractions(feature) + } + + @Test + fun `feature does not subscribe if not a new account`() { + val feature: AutoPushFeature = mock() + val observer = AccountObserver(feature) + + observer.onAuthenticated(mock(), false) + + verifyNoMoreInteractions(feature) + } + + @Test + fun `feature and service invoked on logout`() { + val feature: AutoPushFeature = mock() + val observer = AccountObserver(feature) + + observer.onLoggedOut() + + verify(feature).unsubscribeForType(PushType.Services) + + verifyNoMoreInteractions(feature) + } + + @Test + fun `feature and service not invoked for any other callback`() { + val feature: AutoPushFeature = mock() + val observer = AccountObserver(feature) + + observer.onAuthenticationProblems() + observer.onProfileUpdated(mock()) + + verifyNoMoreInteractions(feature) + } +} \ No newline at end of file diff --git a/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/DeviceObserverTest.kt b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/DeviceObserverTest.kt new file mode 100644 index 00000000000..4add6e0e925 --- /dev/null +++ b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/DeviceObserverTest.kt @@ -0,0 +1,49 @@ +/* + * 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 mozilla.components.feature.sendtab + +import mozilla.components.concept.sync.Device +import mozilla.components.concept.sync.DeviceEvent +import mozilla.components.concept.sync.TabData +import mozilla.components.support.test.any +import mozilla.components.support.test.eq +import mozilla.components.support.test.mock +import org.junit.Test +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +class DeviceObserverTest { + @Test + fun `events are delivered successfully`() { + val callback: (Device?, List) -> Unit = mock() + val observer = DeviceObserver(callback) + val events = listOf(DeviceEvent.TabReceived(mock(), mock())) + + observer.onEvents(events) + + verify(callback).invoke(any(), any()) + + observer.onEvents(listOf(DeviceEvent.TabReceived(null, mock()))) + + verify(callback).invoke(eq(null), any()) + } + + @Test + fun `only TabReceived events are delivered`() { + // we don't have other event types right now so this is a basic test. + val callback: (Device?, List) -> Unit = mock() + val observer = DeviceObserver(callback) + val events = listOf( + DeviceEvent.TabReceived(mock(), mock()), + DeviceEvent.TabReceived(mock(), mock()) + ) + + observer.onEvents(events) + + verify(callback, times(2)).invoke(any(), any()) + } +} \ No newline at end of file diff --git a/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/PushObserverTest.kt b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/PushObserverTest.kt new file mode 100644 index 00000000000..3956ad61683 --- /dev/null +++ b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/PushObserverTest.kt @@ -0,0 +1,90 @@ +/* + * 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 mozilla.components.feature.sendtab + +import mozilla.components.concept.sync.DeviceConstellation +import mozilla.components.concept.sync.OAuthAccount +import mozilla.components.feature.push.AutoPushSubscription +import mozilla.components.feature.push.PushType +import mozilla.components.service.fxa.manager.FxaAccountManager +import mozilla.components.support.test.any +import mozilla.components.support.test.mock +import org.junit.Test +import org.mockito.Mockito.`when` +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +class PushObserverTest { + + @Test + fun `subscription is forwarded to account manager`() { + val manager: FxaAccountManager = mock() + val account: OAuthAccount = mock() + val constellation: DeviceConstellation = mock() + val observer = PushObserver(manager) + val subscription = generateSubscription(PushType.Services) + + `when`(manager.authenticatedAccount()).thenReturn(account) + `when`(account.deviceConstellation()).thenReturn(constellation) + + observer.onSubscriptionAvailable(subscription) + + verify(constellation).setDevicePushSubscriptionAsync(any()) + } + + @Test + fun `subscription is not forwarded if it's not for fxa`() { + val manager: FxaAccountManager = mock() + val account: OAuthAccount = mock() + val constellation: DeviceConstellation = mock() + val observer = PushObserver(manager) + val subscription = generateSubscription(PushType.WebPush) + + `when`(manager.authenticatedAccount()).thenReturn(account) + `when`(account.deviceConstellation()).thenReturn(constellation) + + observer.onSubscriptionAvailable(subscription) + + verify(constellation, never()).setDevicePushSubscriptionAsync(any()) + } + + @Test + fun `messages are forwarded to account manager`() { + val manager: FxaAccountManager = mock() + val account: OAuthAccount = mock() + val constellation: DeviceConstellation = mock() + val observer = PushObserver(manager) + + `when`(manager.authenticatedAccount()).thenReturn(account) + `when`(account.deviceConstellation()).thenReturn(constellation) + + observer.onEvent(PushType.Services, "foobar") + + verify(constellation).processRawEventAsync("foobar") + } + + @Test + fun `account manager is not invoked if no account is available`() { + val manager: FxaAccountManager = mock() + val constellation: DeviceConstellation = mock() + val observer = PushObserver(manager) + val subscription = generateSubscription(PushType.Services) + + observer.onSubscriptionAvailable(subscription) + observer.onEvent(PushType.Services, "foobar") + + verify(constellation, never()).setDevicePushSubscriptionAsync(any()) + verify(constellation, never()).processRawEventAsync("foobar") + } + + private fun generateSubscription(type: PushType) = AutoPushSubscription( + type = type, + endpoint = "https://endpoint.push.mozilla.com", + publicKey = "1234", + authKey = "myKey" + ) +} \ No newline at end of file diff --git a/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabFeatureKtTest.kt b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabFeatureKtTest.kt new file mode 100644 index 00000000000..2095d552785 --- /dev/null +++ b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabFeatureKtTest.kt @@ -0,0 +1,78 @@ +/* + * 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 mozilla.components.feature.sendtab + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runBlockingTest +import mozilla.components.concept.sync.DeviceConstellation +import mozilla.components.concept.sync.OAuthAccount +import mozilla.components.feature.push.AutoPushFeature +import mozilla.components.service.fxa.manager.FxaAccountManager +import mozilla.components.support.test.any +import mozilla.components.support.test.mock +import org.junit.Test +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.Mockito.`when` +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +@ExperimentalCoroutinesApi +class SendTabFeatureKtTest { + @Test + fun `feature register all observers`() = runBlockingTest { + val accountManager: FxaAccountManager = mock() + val pushFeature: AutoPushFeature = mock() + + SendTabFeature( + accountManager = accountManager, + pushFeature = pushFeature, + onTabsReceived = mock() + ) + + verify(accountManager).register(any(), any(), anyBoolean()) + verify(accountManager).registerForDeviceEvents(any(), any(), anyBoolean()) + + verify(pushFeature).registerForPushMessages(any(), any(), any(), anyBoolean()) + verify(pushFeature).registerForSubscriptions(any(), any(), anyBoolean()) + } + + @Test + fun `feature registers only the device observer`() { + val accountManager: FxaAccountManager = mock() + val pushFeature: AutoPushFeature = mock() + + SendTabFeature( + accountManager = accountManager, + onTabsReceived = mock() + ) + + verify(accountManager).registerForDeviceEvents(any(), any(), anyBoolean()) + + verify(accountManager, never()).register(any(), any(), anyBoolean()) + verify(pushFeature, never()).registerForPushMessages(any(), any(), any(), anyBoolean()) + verify(pushFeature, never()).registerForSubscriptions(any(), any(), anyBoolean()) + } + + @Test + fun `block is executed only account is available`() { + val accountManager: FxaAccountManager = mock() + val block: (DeviceConstellation) -> Unit = mock() + val account: OAuthAccount = mock() + val constellation: DeviceConstellation = mock() + + accountManager.withConstellation(block) + + verify(block, never()).invoke(constellation) + + `when`(accountManager.authenticatedAccount()).thenReturn(account) + `when`(account.deviceConstellation()).thenReturn(constellation) + + accountManager.withConstellation(block) + + verify(block).invoke(constellation) + } +} \ No newline at end of file diff --git a/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabUseCasesTest.kt b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabUseCasesTest.kt index da4af5cbe55..287fb8c5da6 100644 --- a/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabUseCasesTest.kt +++ b/components/feature/sendtab/src/test/java/mozilla/components/feature/sendtab/SendTabUseCasesTest.kt @@ -222,27 +222,25 @@ class SendTabUseCasesTest { } @Test - fun `SendTabUseCase - result is false if any send tab action fails`() { - val useCases = SendTabUseCases(manager) + fun `SendTabUseCase - result is false if any send tab action fails`() = runBlockingTest { + val useCases = SendTabUseCases(manager, coroutineContext) val device: Device = mock() val tab = TabData("Title", "http://example.com") - runBlocking { - useCases.sendToDeviceAsync("123", listOf(tab, tab)) + useCases.sendToDeviceAsync("123", listOf(tab, tab)) - verify(constellation, never()).sendEventToDeviceAsync(any(), any()) + verify(constellation, never()).sendEventToDeviceAsync(any(), any()) - `when`(device.id).thenReturn("123") - `when`(state.otherDevices).thenReturn(listOf(device)) - `when`(constellation.sendEventToDeviceAsync(any(), any())) - .thenReturn(CompletableDeferred(true)) - .thenReturn(CompletableDeferred(true)) + `when`(device.id).thenReturn("123") + `when`(state.otherDevices).thenReturn(listOf(device)) + `when`(constellation.sendEventToDeviceAsync(any(), any())) + .thenReturn(CompletableDeferred(true)) + .thenReturn(CompletableDeferred(true)) - val result = useCases.sendToDeviceAsync("123", listOf(tab, tab)) + val result = useCases.sendToDeviceAsync("123", listOf(tab, tab)) - verify(constellation, never()).sendEventToDeviceAsync(any(), any()) - Assert.assertFalse(result.await()) - } + verify(constellation, never()).sendEventToDeviceAsync(any(), any()) + Assert.assertFalse(result.await()) } @Test From 87f5ad279c4fc8aa6e18dbe749c95f73752c4500 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Fri, 2 Aug 2019 14:46:45 -0400 Subject: [PATCH 03/38] Add changelog for SendTabFeature --- docs/changelog.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index c06db1582fb..87a2d926395 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -22,6 +22,19 @@ permalink: /changelog/ * ⚠️ **This is a breaking change**: The `BrowserToolbar.siteSecurityColor` property has been replaced with the setter `BrowserToolbar.setSiteSecurityColor`. * Added `BrowserToolbar.siteSecurityIcons` to use custom security icons with multiple colors in the toolbar. +* **feature-sendtab** + * Added a `SendTabFeature` that observes account device events with optional support for push notifications. + + ```kotlin + SendTabFeature( + context, + accountManager, + pushFeature, // optional + pushService // optional; if you want the service to also be started/stopped based on account changes. + onTabsReceiver = { from, tabs -> /* Do cool things here! */ } + ) + ``` + # 7.0.0 * [Commits](https://github.com/mozilla-mobile/android-components/compare/v6.0.2...v7.0.0) From 5ec752f2587432e369b905f6de68cebabfd63ada Mon Sep 17 00:00:00 2001 From: Alessio Placitelli Date: Fri, 2 Aug 2019 17:09:06 +0200 Subject: [PATCH 04/38] Test the 'baseline' ping in the glean-sample app This adds an instrumented test that sends the app to background, triggers a ping and then validates the received data. --- .../service/glean/config/Configuration.kt | 3 +- .../service/glean/testing/GleanTestRule.kt | 8 +- samples/glean/build.gradle | 4 +- .../mozilla/samples/glean/GleanTestRunner.kt | 89 ++++++++++++ .../mozilla/samples/glean/MainActivityTest.kt | 6 +- .../samples/glean/pings/BaselinePingTest.kt | 134 ++++++++++++++++++ samples/glean/src/main/AndroidManifest.xml | 6 + 7 files changed, 245 insertions(+), 5 deletions(-) create mode 100644 samples/glean/src/androidTest/java/org/mozilla/samples/glean/GleanTestRunner.kt create mode 100644 samples/glean/src/androidTest/java/org/mozilla/samples/glean/pings/BaselinePingTest.kt 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 cd9501e0b4e..97d8b35be8c 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 @@ -46,13 +46,14 @@ data class Configuration internal constructor( // constructor and only initialized with a proper default when calling the primary // constructor from the secondary, public one, below. constructor( + serverEndpoint: String = DEFAULT_TELEMETRY_ENDPOINT, connectionTimeout: Long = DEFAULT_CONNECTION_TIMEOUT, readTimeout: Long = DEFAULT_READ_TIMEOUT, maxEvents: Int = DEFAULT_MAX_EVENTS, httpClient: Lazy = lazy { HttpURLConnectionClient() }, channel: String? = null ) : this ( - serverEndpoint = DEFAULT_TELEMETRY_ENDPOINT, + serverEndpoint = serverEndpoint, userAgent = DEFAULT_USER_AGENT, connectionTimeout = connectionTimeout, readTimeout = readTimeout, diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt index 384decc65bf..9e32e06907c 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt @@ -25,10 +25,14 @@ import org.junit.runner.Description * @get:Rule * val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) * ``` + * + * @param context the application context + * @param configToUse an optional [Configuration] to initialize the Glean SDK with */ @VisibleForTesting(otherwise = VisibleForTesting.NONE) class GleanTestRule( - val context: Context + val context: Context, + val configToUse: Configuration = Configuration() ) : TestWatcher() { override fun starting(description: Description?) { // We're using the WorkManager in a bunch of places, and Glean will crash @@ -37,7 +41,7 @@ class GleanTestRule( Glean.resetGlean( context = context, - config = Configuration(), + config = configToUse, clearStores = true ) } diff --git a/samples/glean/build.gradle b/samples/glean/build.gradle index 9ff58a491b3..4f52f964a79 100644 --- a/samples/glean/build.gradle +++ b/samples/glean/build.gradle @@ -20,7 +20,7 @@ android { versionCode 1 versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "org.mozilla.samples.glean.GleanTestRunner" } buildTypes { @@ -51,8 +51,10 @@ dependencies { androidTestImplementation Dependencies.androidx_test_runner androidTestImplementation Dependencies.androidx_test_rules androidTestImplementation Dependencies.androidx_test_junit + androidTestImplementation Dependencies.androidx_test_uiautomator androidTestImplementation Dependencies.androidx_espresso_core androidTestImplementation Dependencies.androidx_work_testing + androidTestImplementation Dependencies.testing_mockwebserver } apply from: '../../components/service/glean/scripts/sdk_generator.gradle' diff --git a/samples/glean/src/androidTest/java/org/mozilla/samples/glean/GleanTestRunner.kt b/samples/glean/src/androidTest/java/org/mozilla/samples/glean/GleanTestRunner.kt new file mode 100644 index 00000000000..a9003146d17 --- /dev/null +++ b/samples/glean/src/androidTest/java/org/mozilla/samples/glean/GleanTestRunner.kt @@ -0,0 +1,89 @@ +/* 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.samples.glean + +import androidx.annotation.VisibleForTesting +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnitRunner +import okhttp3.mockwebserver.Dispatcher +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import okhttp3.mockwebserver.RecordedRequest + +/** + * Create a mock webserver that accepts all requests and replies with "OK". + * @return a [MockWebServer] instance + */ +private fun createMockWebServer(): MockWebServer { + val server = MockWebServer() + server.setDispatcher(object : Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + return MockResponse().setBody("OK") + } + }) + return server +} + +/** + * Returns the currently active instance of the ping server. + * + * @return the active [MockWebServer] instance + */ +@VisibleForTesting(otherwise = VisibleForTesting.NONE) +internal fun getPingServer(): MockWebServer { + val testRunner: GleanTestRunner = InstrumentationRegistry.getInstrumentation() as GleanTestRunner + return testRunner.pingServer +} + +/** + * Returns the address the local ping server is listening to. + * + * @return a `String` containing the server address. + */ +@VisibleForTesting(otherwise = VisibleForTesting.NONE) +internal fun getPingServerAddress(): String { + val testRunner: GleanTestRunner = InstrumentationRegistry.getInstrumentation() as GleanTestRunner + return testRunner.pingServerAddress!! +} + +/** + * The test runner to be used in the instrumentation tests for the Glean SDK + * sample app in order to point it to a local ping server. + */ +@VisibleForTesting(otherwise = VisibleForTesting.NONE) +class GleanTestRunner : AndroidJUnitRunner() { + // Add a lazy ping server to the app runner. This is only initialized once + // since the `Application` object is re-used. + internal val pingServer: MockWebServer by lazy { createMockWebServer() } + internal var pingServerAddress: String? = null + + init { + // We need to start the server off the main thread, otherwise + // Android will throw a `NetworkOnMainThreadException`. Spawning + // a thread and joining seems fine. + val thread = Thread { + pingServer.start() + pingServerAddress = "http://${pingServer.hostName}:${pingServer.port}" + } + thread.start() + thread.join() + } + + /** + * Called before the application code runs, this starts the ping server. + */ + override fun onStart() { + super.onStart() + pingServer.start() + } + + /** + * Called after the application code cleans up, this stops the ping server. + */ + override fun onDestroy() { + super.onDestroy() + pingServer.shutdown() + } +} diff --git a/samples/glean/src/androidTest/java/org/mozilla/samples/glean/MainActivityTest.kt b/samples/glean/src/androidTest/java/org/mozilla/samples/glean/MainActivityTest.kt index 28db63e9b95..a291449df03 100644 --- a/samples/glean/src/androidTest/java/org/mozilla/samples/glean/MainActivityTest.kt +++ b/samples/glean/src/androidTest/java/org/mozilla/samples/glean/MainActivityTest.kt @@ -10,6 +10,7 @@ import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.rule.ActivityTestRule +import mozilla.components.service.glean.config.Configuration import mozilla.components.service.glean.testing.GleanTestRule import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -25,7 +26,10 @@ class MainActivityTest { val activityRule: ActivityTestRule = ActivityTestRule(MainActivity::class.java) @get:Rule - val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) + val gleanRule = GleanTestRule( + ApplicationProvider.getApplicationContext(), + Configuration(serverEndpoint = getPingServerAddress()) + ) @Test fun checkGleanClickData() { diff --git a/samples/glean/src/androidTest/java/org/mozilla/samples/glean/pings/BaselinePingTest.kt b/samples/glean/src/androidTest/java/org/mozilla/samples/glean/pings/BaselinePingTest.kt new file mode 100644 index 00000000000..aa3cd92c8ef --- /dev/null +++ b/samples/glean/src/androidTest/java/org/mozilla/samples/glean/pings/BaselinePingTest.kt @@ -0,0 +1,134 @@ +/* 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.samples.glean.pings + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import org.junit.Assert.assertEquals + +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.samples.glean.MainActivity +import org.mozilla.samples.glean.getPingServer +import androidx.test.uiautomator.UiDevice +import androidx.work.WorkInfo +import androidx.work.WorkManager +import androidx.work.testing.WorkManagerTestInitHelper +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import mozilla.components.service.glean.config.Configuration +import mozilla.components.service.glean.testing.GleanTestRule +import org.json.JSONObject +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.mozilla.samples.glean.getPingServerAddress +import java.util.concurrent.TimeUnit + +@RunWith(AndroidJUnit4::class) +class BaselinePingTest { + @get:Rule + val activityRule: ActivityTestRule = ActivityTestRule(MainActivity::class.java) + + @get:Rule + val gleanRule = GleanTestRule( + ApplicationProvider.getApplicationContext(), + Configuration(serverEndpoint = getPingServerAddress()) + ) + + @Before + fun clearWorkManager() { + val context = ApplicationProvider.getApplicationContext() + WorkManagerTestInitHelper.initializeTestWorkManager(context) + } + + private fun waitForPingContent( + pingName: String, + maxAttempts: Int = 3 + ): JSONObject? + { + val server = getPingServer() + + var attempts = 0 + do { + attempts += 1 + val request = server.takeRequest(20L, TimeUnit.SECONDS) + val docType = request.path.split("/")[3] + if (pingName == docType) { + return JSONObject(request.body.readUtf8()) + } + } while (attempts < maxAttempts) + + return null + } + + /** + * Sadly, the WorkManager still requires us to manually trigger the upload job. + * This function goes through all the active jobs by Glean (there should only be + * one!) and triggers them. + */ + private fun triggerEnqueuedUpload() { + // The tag is really internal to PingUploadWorker, but we can't do much more + // than copy-paste unless we want to increase our API surface. + val tag = "mozac_service_glean_ping_upload_worker" + val reasonablyHighCITimeoutMs = 5000L + + runBlocking { + withTimeout(reasonablyHighCITimeoutMs) { + do { + val workInfoList = WorkManager.getInstance().getWorkInfosByTag(tag).get() + workInfoList.forEach { workInfo -> + if (workInfo.state === WorkInfo.State.ENQUEUED) { + // Trigger WorkManager using TestDriver + val testDriver = WorkManagerTestInitHelper.getTestDriver() + testDriver.setAllConstraintsMet(workInfo.id) + return@withTimeout + } + } + } while (true) + } + } + } + + @Test + fun validateBaselinePing() { + // Wait for the app to be idle/ready. + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.waitForIdle() + + // Wait for 1 second: this should guarantee we have some valid duration in the + // ping. + Thread.sleep(1000) + + // Move it to background. + device.pressHome() + + // Wait for the upload job to be present and trigger it. + Thread.sleep(1000) // FIXME: for some reason, without this, WorkManager won't find the job + triggerEnqueuedUpload() + + // Validate the received data. + val baselinePing = waitForPingContent("baseline")!! + assertEquals("baseline", baselinePing.getJSONObject("ping_info")["ping_type"]) + + val metrics = baselinePing.getJSONObject("metrics") + + // Make sure we have a 'duration' field with a reasonable value: it should be >= 1, since + // we slept for 1000ms. + val timespans = metrics.getJSONObject("timespan") + assertTrue(timespans.getJSONObject("glean.baseline.duration").getLong("value") >= 1L) + + // Make sure there's no errors. + val errors = metrics.optJSONObject("labeled_counter")?.keys() + errors?.forEach { + assertFalse(it.startsWith("glean.error.")) + } + } +} diff --git a/samples/glean/src/main/AndroidManifest.xml b/samples/glean/src/main/AndroidManifest.xml index b1715f78ea2..8b6f2f6efef 100644 --- a/samples/glean/src/main/AndroidManifest.xml +++ b/samples/glean/src/main/AndroidManifest.xml @@ -3,12 +3,16 @@ - 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/. --> + Date: Fri, 9 Aug 2019 12:12:02 +0000 Subject: [PATCH 05/38] Update docs (20190809-121201) --- docs/api/alltypes/index.md | 4 ++- docs/api/index.md | 3 +- .../-site-security-icons/-init-.md | 8 +++++ .../get-default-security-icons.md | 5 +++ .../-site-security-icons/index.md | 32 +++++++++++++++++++ .../-site-security-icons/insecure.md | 11 +++++++ .../-site-security-icons/secure.md | 11 +++++++ .../-site-security-icons/with-color-filter.md | 12 +++++++ .../index.md | 9 ++++++ .../apply-autocomplete-result.md | 2 +- .../coroutine-context.md | 2 +- .../-async-autocomplete-delegate/index.md | 2 +- .../no-autocomplete-result.md | 2 +- .../coroutine-context.md | 2 +- .../-async-filter-listener/index.md | 2 +- .../-async-filter-listener/invoke.md | 2 +- .../-browser-toolbar/-button/index.md | 2 +- .../-browser-toolbar/-button/padding.md | 2 +- .../-browser-toolbar/-toggle-button/index.md | 2 +- .../-toggle-button/padding.md | 2 +- .../-two-state-button/bind.md | 2 +- .../-two-state-button/enabled.md | 2 +- .../-two-state-button/index.md | 2 +- .../-browser-toolbar/add-browser-action.md | 2 +- .../-browser-toolbar/add-edit-action.md | 2 +- .../-browser-toolbar/add-navigation-action.md | 2 +- .../-browser-toolbar/add-page-action.md | 2 +- .../-browser-toolbar/browser-action-margin.md | 2 +- .../-browser-toolbar/clear-view-color.md | 2 +- .../-browser-toolbar/display-mode.md | 2 +- .../-browser-toolbar/display-progress.md | 2 +- .../display-site-security-icon.md | 2 +- .../display-tracking-protection-icon.md | 2 +- .../-browser-toolbar/edit-mode.md | 2 +- .../-browser-toolbar/focus.md | 2 +- .../-browser-toolbar/hint-color.md | 2 +- .../-browser-toolbar/hint.md | 2 +- .../-browser-toolbar/index.md | 5 +-- .../-browser-toolbar/invalidate-actions.md | 2 +- .../-browser-toolbar/menu-view-color.md | 2 +- .../-browser-toolbar/on-back-pressed.md | 2 +- .../-browser-toolbar/on-layout.md | 2 +- .../-browser-toolbar/on-measure.md | 2 +- .../-browser-toolbar/on-url-clicked.md | 2 +- .../-browser-toolbar/private.md | 2 +- .../-browser-toolbar/progress-bar-gravity.md | 2 +- .../-browser-toolbar/separator-color.md | 2 +- .../set-autocomplete-listener.md | 2 +- .../-browser-toolbar/set-menu-builder.md | 2 +- .../set-on-edit-focus-change-listener.md | 2 +- .../-browser-toolbar/set-on-edit-listener.md | 2 +- .../set-on-site-security-clicked-listener.md | 2 +- ...on-tracking-protection-clicked-listener.md | 2 +- .../set-on-url-commit-listener.md | 2 +- .../set-on-url-long-click-listener.md | 2 +- .../-browser-toolbar/set-search-terms.md | 2 +- .../set-site-security-color.md | 5 +++ .../set-tracking-protection-icons.md | 2 +- .../-browser-toolbar/set-url-text-padding.md | 2 +- .../-browser-toolbar/site-secure.md | 2 +- .../-browser-toolbar/site-security-color.md | 9 ------ .../-browser-toolbar/site-security-icons.md | 9 ++++++ .../site-tracking-protection.md | 2 +- .../suggestion-background-color.md | 2 +- .../suggestion-foreground-color.md | 2 +- .../-browser-toolbar/text-color.md | 2 +- .../-browser-toolbar/text-size.md | 2 +- .../-browser-toolbar/title-color.md | 2 +- .../-browser-toolbar/title-text-size.md | 2 +- .../-browser-toolbar/title.md | 2 +- .../-browser-toolbar/typeface.md | 2 +- .../-browser-toolbar/url-box-margin.md | 2 +- .../-browser-toolbar/url-box-view.md | 2 +- .../-browser-toolbar/url.md | 2 +- .../force-registration-renewal.md | 5 ++- .../-auto-push-feature/subscribe-all.md | 2 +- .../unsubscribe-for-type.md | 5 ++- .../-auto-push-subscription/auth-key.md | 2 +- .../-auto-push-subscription/endpoint.md | 2 +- .../-auto-push-subscription/index.md | 2 +- .../-auto-push-subscription/public-key.md | 2 +- .../-auto-push-subscription/type.md | 2 +- .../-protocol/-h-t-t-p-s.md | 2 +- .../-protocol/-h-t-t-p.md | 2 +- .../-protocol/index.md | 2 +- .../-push-config/index.md | 2 +- .../-push-config/protocol.md | 2 +- .../-push-config/sender-id.md | 2 +- .../-push-config/server-host.md | 2 +- .../-push-config/service-type.md | 2 +- .../-push-subscription-observer/index.md | 2 +- .../on-subscription-available.md | 2 +- .../-push-type/-services.md | 2 +- .../-push-type/-web-push.md | 2 +- .../-push-type/index.md | 2 +- .../-push-type/to-channel-id.md | 2 +- .../-service-type/-a-d-m.md | 2 +- .../-service-type/-f-c-m.md | 2 +- .../-service-type/index.md | 2 +- .../-send-tab-feature/-init-.md | 25 +++++++++++++++ .../-send-tab-feature/index.md | 31 ++++++++++++++++++ .../index.md | 1 + ...l-t_-c-o-n-n-e-c-t-i-o-n_-t-i-m-e-o-u-t.md | 2 +- .../-d-e-f-a-u-l-t_-l-o-g_-p-i-n-g-s.md | 2 +- .../-d-e-f-a-u-l-t_-m-a-x_-e-v-e-n-t-s.md | 2 +- .../-d-e-f-a-u-l-t_-r-e-a-d_-t-i-m-e-o-u-t.md | 2 +- ...l-t_-t-e-l-e-m-e-t-r-y_-e-n-d-p-o-i-n-t.md | 2 +- .../-d-e-f-a-u-l-t_-u-s-e-r_-a-g-e-n-t.md | 2 +- .../-configuration/-init-.md | 2 +- .../-configuration/index.md | 2 +- .../-glean-test-rule/-init-.md | 7 +++- .../-glean-test-rule/config-to-use.md | 8 +++++ .../-glean-test-rule/context.md | 5 ++- .../-glean-test-rule/index.md | 13 ++++++-- .../-glean-test-rule/starting.md | 2 +- .../get-upload-enabled.md | 2 +- .../handle-background-event.md | 2 +- .../-glean-internal-a-p-i/index.md | 2 +- .../-glean-internal-a-p-i/initialize.md | 2 +- .../-glean-internal-a-p-i/is-initialized.md | 2 +- .../-glean-internal-a-p-i/register-pings.md | 2 +- .../set-experiment-active.md | 2 +- .../set-experiment-inactive.md | 2 +- .../set-upload-enabled.md | 2 +- .../test-get-experiment-data.md | 2 +- .../test-is-experiment-active.md | 2 +- .../-glean.md | 2 +- .../-webserver-rule/-init-.md | 2 +- .../-webserver-rule/finished.md | 4 +-- .../-webserver-rule/index.md | 4 +-- .../-webserver-rule/starting.md | 4 +-- .../-webserver-rule/url.md | 4 +-- .../index.md | 4 +-- docs/api/package-list | 3 +- 134 files changed, 321 insertions(+), 137 deletions(-) create mode 100644 docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/-init-.md create mode 100644 docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/get-default-security-icons.md create mode 100644 docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/index.md create mode 100644 docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/insecure.md create mode 100644 docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/secure.md create mode 100644 docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/with-color-filter.md create mode 100644 docs/api/mozilla.components.browser.toolbar.display/index.md create mode 100644 docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-site-security-color.md delete mode 100644 docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-color.md create mode 100644 docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-icons.md create mode 100644 docs/api/mozilla.components.feature.sendtab/-send-tab-feature/-init-.md create mode 100644 docs/api/mozilla.components.feature.sendtab/-send-tab-feature/index.md create mode 100644 docs/api/mozilla.components.service.glean.testing/-glean-test-rule/config-to-use.md rename docs/api/{mozilla.components.support.test.rules => mozilla.components.support.android.test.rules}/-webserver-rule/-init-.md (66%) rename docs/api/{mozilla.components.support.test.rules => mozilla.components.support.android.test.rules}/-webserver-rule/finished.md (54%) rename docs/api/{mozilla.components.support.test.rules => mozilla.components.support.android.test.rules}/-webserver-rule/index.md (86%) rename docs/api/{mozilla.components.support.test.rules => mozilla.components.support.android.test.rules}/-webserver-rule/starting.md (54%) rename docs/api/{mozilla.components.support.test.rules => mozilla.components.support.android.test.rules}/-webserver-rule/url.md (61%) rename docs/api/{mozilla.components.support.test.rules => mozilla.components.support.android.test.rules}/index.md (75%) diff --git a/docs/api/alltypes/index.md b/docs/api/alltypes/index.md index 2af7c22d39c..7f8e4b112a6 100644 --- a/docs/api/alltypes/index.md +++ b/docs/api/alltypes/index.md @@ -443,6 +443,7 @@ | [org.mozilla.telemetry.measurement.SearchesMeasurement](../org.mozilla.telemetry.measurement/-searches-measurement/index.md) | A TelemetryMeasurement implementation to count the number of times a user has searched with a specific engine from a specific location. | | [mozilla.components.browser.state.state.SecurityInfoState](../mozilla.components.browser.state.state/-security-info-state/index.md) | A value type holding security information for a Session. | | [mozilla.components.browser.session.SelectionAwareSessionObserver](../mozilla.components.browser.session/-selection-aware-session-observer/index.md) | This class is a combination of [Session.Observer](../mozilla.components.browser.session/-session/-observer/index.md) and [SessionManager.Observer](../mozilla.components.browser.session/-session-manager/-observer/index.md). It provides functionality to observe changes to a specified or selected session, and can automatically take care of switching over the observer in case a different session gets selected (see [observeFixed](../mozilla.components.browser.session/-selection-aware-session-observer/observe-fixed.md) and [observeSelected](../mozilla.components.browser.session/-selection-aware-session-observer/observe-selected.md)). | +| [mozilla.components.feature.sendtab.SendTabFeature](../mozilla.components.feature.sendtab/-send-tab-feature/index.md) | A feature that uses the [FxaAccountManager](../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md) to send and receive tabs with optional push support for receiving tabs from the [AutoPushFeature](../mozilla.components.feature.push/-auto-push-feature/index.md) and a [PushService](../mozilla.components.concept.push/-push-service/index.md). | | [mozilla.components.feature.sendtab.SendTabUseCases](../mozilla.components.feature.sendtab/-send-tab-use-cases/index.md) | Contains use cases for sending tabs to devices related to the firefox-accounts. | | [mozilla.components.lib.crash.service.SentryService](../mozilla.components.lib.crash.service/-sentry-service/index.md) | A [CrashReporterService](../mozilla.components.lib.crash.service/-crash-reporter-service/index.md) implementation that uploads crash reports to a Sentry server. | | [org.mozilla.telemetry.measurement.SequenceMeasurement](../org.mozilla.telemetry.measurement/-sequence-measurement/index.md) | | @@ -477,6 +478,7 @@ | [mozilla.components.feature.sitepermissions.SitePermissionsFeature](../mozilla.components.feature.sitepermissions/-site-permissions-feature/index.md) | This feature will subscribe to the currently selected [Session](../mozilla.components.browser.session/-session/index.md) and display a suitable dialogs based on [Session.Observer.onAppPermissionRequested](../mozilla.components.browser.session/-session/-observer/on-app-permission-requested.md) or [Session.Observer.onContentPermissionRequested](../mozilla.components.browser.session/-session/-observer/on-content-permission-requested.md) events. Once the dialog is closed the [PermissionRequest](../mozilla.components.concept.engine.permission/-permission-request/index.md) will be consumed. | | [mozilla.components.feature.sitepermissions.SitePermissionsRules](../mozilla.components.feature.sitepermissions/-site-permissions-rules/index.md) | Indicate how site permissions must behave by permission category. | | [mozilla.components.feature.sitepermissions.SitePermissionsStorage](../mozilla.components.feature.sitepermissions/-site-permissions-storage/index.md) | A storage implementation to save [SitePermissions](../mozilla.components.feature.sitepermissions/-site-permissions/index.md). | +| [mozilla.components.browser.toolbar.display.SiteSecurityIcons](../mozilla.components.browser.toolbar.display/-site-security-icons/index.md) | Specifies icons to display in the toolbar representing the security of the current website. | | [mozilla.components.concept.engine.manifest.Size](../mozilla.components.concept.engine.manifest/-size/index.md) | Represents dimensions for an image. Corresponds to values of the "sizes" HTML attribute. | | [mozilla.components.browser.session.storage.SnapshotSerializer](../mozilla.components.browser.session.storage/-snapshot-serializer/index.md) | Helper to transform [SessionManager.Snapshot](../mozilla.components.browser.session/-session-manager/-snapshot/index.md) instances to JSON and back. | | [mozilla.components.lib.state.State](../mozilla.components.lib.state/-state.md) | Generic interface for a [State](../mozilla.components.lib.state/-state.md) maintained by a [Store](../mozilla.components.lib.state/-store/index.md). | @@ -604,7 +606,7 @@ | [mozilla.components.feature.pwa.WebAppUseCases](../mozilla.components.feature.pwa/-web-app-use-cases/index.md) | These use cases allow for adding a web app or web site to the homescreen. | | [mozilla.components.concept.engine.webextension.WebExtension](../mozilla.components.concept.engine.webextension/-web-extension/index.md) | Represents a browser extension based on the WebExtension API: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions | | [mozilla.components.support.utils.WebURLFinder](../mozilla.components.support.utils/-web-u-r-l-finder/index.md) | Regular expressions used in this class are taken from Android's Patterns.java. We brought them in to standardize URL matching across Android versions, instead of relying on Android version-dependent built-ins that can vary across Android versions. The original code can be found here: http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/util/Patterns.java | -| [mozilla.components.support.test.rules.WebserverRule](../mozilla.components.support.test.rules/-webserver-rule/index.md) | A [TestWatcher](#) junit rule that will serve content from assets in the test package. | +| [mozilla.components.support.android.test.rules.WebserverRule](../mozilla.components.support.android.test.rules/-webserver-rule/index.md) | A [TestWatcher](#) junit rule that will serve content from assets in the test package. | | [mozilla.components.feature.session.WindowFeature](../mozilla.components.feature.session/-window-feature/index.md) | Feature implementation for handling window requests. | | [mozilla.components.concept.engine.window.WindowRequest](../mozilla.components.concept.engine.window/-window-request/index.md) | Represents a request to open or close a browser window. | | [mozilla.components.service.fxa.sync.WorkManagerSyncDispatcher](../mozilla.components.service.fxa.sync/-work-manager-sync-dispatcher/index.md) | | diff --git a/docs/api/index.md b/docs/api/index.md index 85bb60f5a05..6d9d8ea4d47 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -56,6 +56,7 @@ | [mozilla.components.browser.tabstray.thumbnail](mozilla.components.browser.tabstray.thumbnail/index.md) | | | [mozilla.components.browser.toolbar](mozilla.components.browser.toolbar/index.md) | | | [mozilla.components.browser.toolbar.behavior](mozilla.components.browser.toolbar.behavior/index.md) | | +| [mozilla.components.browser.toolbar.display](mozilla.components.browser.toolbar.display/index.md) | | | [mozilla.components.concept.awesomebar](mozilla.components.concept.awesomebar/index.md) | | | [mozilla.components.concept.engine](mozilla.components.concept.engine/index.md) | | | [mozilla.components.concept.engine.content.blocking](mozilla.components.concept.engine.content.blocking/index.md) | | @@ -160,6 +161,7 @@ | [mozilla.components.support.android.test.espresso](mozilla.components.support.android.test.espresso/index.md) | | | [mozilla.components.support.android.test.espresso.matcher](mozilla.components.support.android.test.espresso.matcher/index.md) | | | [mozilla.components.support.android.test.leaks](mozilla.components.support.android.test.leaks/index.md) | | +| [mozilla.components.support.android.test.rules](mozilla.components.support.android.test.rules/index.md) | | | [mozilla.components.support.base.android](mozilla.components.support.base.android/index.md) | | | [mozilla.components.support.base.android.view](mozilla.components.support.base.android.view/index.md) | | | [mozilla.components.support.base.facts](mozilla.components.support.base.facts/index.md) | | @@ -188,7 +190,6 @@ | [mozilla.components.support.test.ext](mozilla.components.support.test.ext/index.md) | | | [mozilla.components.support.test.robolectric](mozilla.components.support.test.robolectric/index.md) | | | [mozilla.components.support.test.robolectric.shadow](mozilla.components.support.test.robolectric.shadow/index.md) | | -| [mozilla.components.support.test.rules](mozilla.components.support.test.rules/index.md) | | | [mozilla.components.support.utils](mozilla.components.support.utils/index.md) | | | [mozilla.components.tooling.fetch.tests](mozilla.components.tooling.fetch.tests/index.md) | | | [mozilla.components.tooling.lint](mozilla.components.tooling.lint/index.md) | | diff --git a/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/-init-.md b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/-init-.md new file mode 100644 index 00000000000..1414b42de9e --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/-init-.md @@ -0,0 +1,8 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar.display](../index.md) / [SiteSecurityIcons](index.md) / [<init>](./-init-.md) + +# <init> + +`SiteSecurityIcons(insecure: ?, secure: ?)` + +Specifies icons to display in the toolbar representing the security of the current website. + diff --git a/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/get-default-security-icons.md b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/get-default-security-icons.md new file mode 100644 index 00000000000..fc09a50cc2b --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/get-default-security-icons.md @@ -0,0 +1,5 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar.display](../index.md) / [SiteSecurityIcons](index.md) / [getDefaultSecurityIcons](./get-default-security-icons.md) + +# getDefaultSecurityIcons + +`fun getDefaultSecurityIcons(context: , color: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`SiteSecurityIcons`](index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt#L60) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/index.md b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/index.md new file mode 100644 index 00000000000..004127fa211 --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/index.md @@ -0,0 +1,32 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar.display](../index.md) / [SiteSecurityIcons](./index.md) + +# SiteSecurityIcons + +`data class SiteSecurityIcons` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt#L25) + +Specifies icons to display in the toolbar representing the security of the current website. + +### Constructors + +| Name | Summary | +|---|---| +| [<init>](-init-.md) | `SiteSecurityIcons(insecure: ?, secure: ?)`
Specifies icons to display in the toolbar representing the security of the current website. | + +### Properties + +| Name | Summary | +|---|---| +| [insecure](insecure.md) | `val insecure: ?`
Icon to display for HTTP sites. | +| [secure](secure.md) | `val secure: ?`
Icon to display for HTTPS sites. | + +### Functions + +| Name | Summary | +|---|---| +| [withColorFilter](with-color-filter.md) | `fun withColorFilter(insecureColorFilter: , secureColorFilter: ): `[`SiteSecurityIcons`](./index.md)
Returns an instance of [SiteSecurityIcons](./index.md) with a color filter applied to each icon.`fun withColorFilter(insecureColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, secureColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`SiteSecurityIcons`](./index.md)
Returns an instance of [SiteSecurityIcons](./index.md) with a color tint applied to each icon. | + +### Companion Object Functions + +| Name | Summary | +|---|---| +| [getDefaultSecurityIcons](get-default-security-icons.md) | `fun getDefaultSecurityIcons(context: , color: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`SiteSecurityIcons`](./index.md) | diff --git a/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/insecure.md b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/insecure.md new file mode 100644 index 00000000000..3bab1119908 --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/insecure.md @@ -0,0 +1,11 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar.display](../index.md) / [SiteSecurityIcons](index.md) / [insecure](./insecure.md) + +# insecure + +`val insecure: ?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt#L26) + +Icon to display for HTTP sites. + +### Property + +`insecure` - Icon to display for HTTP sites. \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/secure.md b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/secure.md new file mode 100644 index 00000000000..32f8ca42f4a --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/secure.md @@ -0,0 +1,11 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar.display](../index.md) / [SiteSecurityIcons](index.md) / [secure](./secure.md) + +# secure + +`val secure: ?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt#L27) + +Icon to display for HTTPS sites. + +### Property + +`secure` - Icon to display for HTTPS sites. \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/with-color-filter.md b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/with-color-filter.md new file mode 100644 index 00000000000..565149588ef --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/-site-security-icons/with-color-filter.md @@ -0,0 +1,12 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar.display](../index.md) / [SiteSecurityIcons](index.md) / [withColorFilter](./with-color-filter.md) + +# withColorFilter + +`fun withColorFilter(insecureColorFilter: , secureColorFilter: ): `[`SiteSecurityIcons`](index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt#L33) + +Returns an instance of [SiteSecurityIcons](index.md) with a color filter applied to each icon. + +`fun withColorFilter(insecureColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, secureColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`SiteSecurityIcons`](index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt#L43) + +Returns an instance of [SiteSecurityIcons](index.md) with a color tint applied to each icon. + diff --git a/docs/api/mozilla.components.browser.toolbar.display/index.md b/docs/api/mozilla.components.browser.toolbar.display/index.md new file mode 100644 index 00000000000..22a3de3926d --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar.display/index.md @@ -0,0 +1,9 @@ +[android-components](../index.md) / [mozilla.components.browser.toolbar.display](./index.md) + +## Package mozilla.components.browser.toolbar.display + +### Types + +| Name | Summary | +|---|---| +| [SiteSecurityIcons](-site-security-icons/index.md) | `data class SiteSecurityIcons`
Specifies icons to display in the toolbar representing the security of the current website. | diff --git a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/apply-autocomplete-result.md b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/apply-autocomplete-result.md index b3ccc330795..61bf2358d88 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/apply-autocomplete-result.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/apply-autocomplete-result.md @@ -2,7 +2,7 @@ # applyAutocompleteResult -`fun applyAutocompleteResult(result: `[`AutocompleteResult`](../../mozilla.components.concept.toolbar/-autocomplete-result/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L820) +`fun applyAutocompleteResult(result: `[`AutocompleteResult`](../../mozilla.components.concept.toolbar/-autocomplete-result/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L831) Overrides [AutocompleteDelegate.applyAutocompleteResult](../../mozilla.components.concept.toolbar/-autocomplete-delegate/apply-autocomplete-result.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/coroutine-context.md b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/coroutine-context.md index 7951efc9f40..062822b71fb 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/coroutine-context.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/coroutine-context.md @@ -2,4 +2,4 @@ # coroutineContext -`val coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L817) \ No newline at end of file +`val coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L828) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/index.md b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/index.md index 6992d65121e..ed597d3aa08 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/index.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/index.md @@ -2,7 +2,7 @@ # AsyncAutocompleteDelegate -`class AsyncAutocompleteDelegate : `[`AutocompleteDelegate`](../../mozilla.components.concept.toolbar/-autocomplete-delegate/index.md)`, CoroutineScope` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L814) +`class AsyncAutocompleteDelegate : `[`AutocompleteDelegate`](../../mozilla.components.concept.toolbar/-autocomplete-delegate/index.md)`, CoroutineScope` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L825) An autocomplete delegate which is aware of its parent scope (to check for cancellations). Responsible for processing autocompletion results and discarding stale results when [urlView](#) moved on. diff --git a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/no-autocomplete-result.md b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/no-autocomplete-result.md index a1aabb1d992..559949bd9a2 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/no-autocomplete-result.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-autocomplete-delegate/no-autocomplete-result.md @@ -2,7 +2,7 @@ # noAutocompleteResult -`fun noAutocompleteResult(input: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L844) +`fun noAutocompleteResult(input: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L855) Overrides [AutocompleteDelegate.noAutocompleteResult](../../mozilla.components.concept.toolbar/-autocomplete-delegate/no-autocomplete-result.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/coroutine-context.md b/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/coroutine-context.md index 259191ebba6..613fd9ea552 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/coroutine-context.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/coroutine-context.md @@ -2,4 +2,4 @@ # coroutineContext -`val coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L795) \ No newline at end of file +`val coroutineContext: `[`CoroutineContext`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L806) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/index.md b/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/index.md index bc4cb46debb..c42023599a9 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/index.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/index.md @@ -2,7 +2,7 @@ # AsyncFilterListener -`class AsyncFilterListener : `[`OnFilterListener`](../../mozilla.components.ui.autocomplete/-on-filter-listener.md)`, CoroutineScope` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L793) +`class AsyncFilterListener : `[`OnFilterListener`](../../mozilla.components.ui.autocomplete/-on-filter-listener.md)`, CoroutineScope` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L804) Wraps [filter](#) execution in a coroutine context, cancelling prior executions on every invocation. [coroutineContext](coroutine-context.md) must be of type that doesn't propagate cancellation of its children upwards. diff --git a/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/invoke.md b/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/invoke.md index ed186f8c79f..15566c17ded 100644 --- a/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/invoke.md +++ b/docs/api/mozilla.components.browser.toolbar/-async-filter-listener/invoke.md @@ -2,4 +2,4 @@ # invoke -`fun invoke(text: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L799) \ No newline at end of file +`fun invoke(text: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L810) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/index.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/index.md index 9f16dc77019..a8a9cdb20ab 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/index.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/index.md @@ -2,7 +2,7 @@ # Button -`class Button : `[`ActionButton`](../../../mozilla.components.concept.toolbar/-toolbar/-action-button/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L693) +`class Button : `[`ActionButton`](../../../mozilla.components.concept.toolbar/-toolbar/-action-button/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L704) An action button to be added to the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/padding.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/padding.md index d02359ea53f..bdbe22babad 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/padding.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-button/padding.md @@ -2,7 +2,7 @@ # padding -`val padding: `[`Padding`](../../../mozilla.components.support.base.android/-padding/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L698) +`val padding: `[`Padding`](../../../mozilla.components.support.base.android/-padding/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L709) a custom [Padding](../../../mozilla.components.support.base.android/-padding/index.md) for this Button. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/index.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/index.md index c547cba9824..b7782d0be50 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/index.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/index.md @@ -2,7 +2,7 @@ # ToggleButton -`class ToggleButton : `[`ActionToggleButton`](../../../mozilla.components.concept.toolbar/-toolbar/-action-toggle-button/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L716) +`class ToggleButton : `[`ActionToggleButton`](../../../mozilla.components.concept.toolbar/-toolbar/-action-toggle-button/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L727) An action button with two states, selected and unselected. When the button is pressed, the state changes automatically. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/padding.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/padding.md index 007eac20d0a..f4aa991c82f 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/padding.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-toggle-button/padding.md @@ -2,7 +2,7 @@ # padding -`val padding: `[`Padding`](../../../mozilla.components.support.base.android/-padding/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L724) +`val padding: `[`Padding`](../../../mozilla.components.support.base.android/-padding/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L735) a custom [Padding](../../../mozilla.components.support.base.android/-padding/index.md) for this Button. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/bind.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/bind.md index f0489e1a450..c03fd14aa39 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/bind.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/bind.md @@ -2,7 +2,7 @@ # bind -`open fun bind(view: ): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L767) +`open fun bind(view: ): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L778) Overrides [ActionButton.bind](../../../mozilla.components.concept.toolbar/-toolbar/-action-button/bind.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/enabled.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/enabled.md index 26bbc20b487..ae74c028b4a 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/enabled.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/enabled.md @@ -2,4 +2,4 @@ # enabled -`var enabled: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L764) \ No newline at end of file +`var enabled: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L775) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/index.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/index.md index 31f8cc4d668..007b111aef2 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/index.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/-two-state-button/index.md @@ -2,7 +2,7 @@ # TwoStateButton -`class TwoStateButton : `[`Button`](../-button/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L750) +`class TwoStateButton : `[`Button`](../-button/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L761) An action that either shows an active button or an inactive button based on the provided isEnabled lambda. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-browser-action.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-browser-action.md index 9601f052f0f..d53db8d68fc 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-browser-action.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-browser-action.md @@ -2,7 +2,7 @@ # addBrowserAction -`fun addBrowserAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L574) +`fun addBrowserAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L585) Overrides [Toolbar.addBrowserAction](../../mozilla.components.concept.toolbar/-toolbar/add-browser-action.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-edit-action.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-edit-action.md index 5985ec40fa2..28941786f69 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-edit-action.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-edit-action.md @@ -2,7 +2,7 @@ # addEditAction -`fun addEditAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L599) +`fun addEditAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L610) Overrides [Toolbar.addEditAction](../../mozilla.components.concept.toolbar/-toolbar/add-edit-action.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-navigation-action.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-navigation-action.md index 3eedfb8e6a2..dd284abfa10 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-navigation-action.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-navigation-action.md @@ -2,7 +2,7 @@ # addNavigationAction -`fun addNavigationAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L592) +`fun addNavigationAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L603) Overrides [Toolbar.addNavigationAction](../../mozilla.components.concept.toolbar/-toolbar/add-navigation-action.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-page-action.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-page-action.md index d3122ae0837..86c3c8d8c9f 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-page-action.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/add-page-action.md @@ -2,7 +2,7 @@ # addPageAction -`fun addPageAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L584) +`fun addPageAction(action: `[`Action`](../../mozilla.components.concept.toolbar/-toolbar/-action/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L595) Overrides [Toolbar.addPageAction](../../mozilla.components.concept.toolbar/-toolbar/add-page-action.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/browser-action-margin.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/browser-action-margin.md index dac9d033510..4885adb24ac 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/browser-action-margin.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/browser-action-margin.md @@ -2,7 +2,7 @@ # browserActionMargin -`var browserActionMargin: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L147) +`var browserActionMargin: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L148) Gets/Sets the margin to be used between browser actions. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/clear-view-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/clear-view-color.md index dec151f2847..ff0372f908b 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/clear-view-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/clear-view-color.md @@ -2,7 +2,7 @@ # clearViewColor -`var clearViewColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L140) +`var clearViewColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L141) Gets/Sets the color tint of the cancel button. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-mode.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-mode.md index 8c89f11f033..c4c83f6935b 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-mode.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-mode.md @@ -2,7 +2,7 @@ # displayMode -`fun displayMode(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L627) +`fun displayMode(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L638) Overrides [Toolbar.displayMode](../../mozilla.components.concept.toolbar/-toolbar/display-mode.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-progress.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-progress.md index 470274416a4..0b4ad1b409a 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-progress.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-progress.md @@ -2,7 +2,7 @@ # displayProgress -`fun displayProgress(progress: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L543) +`fun displayProgress(progress: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L554) Overrides [Toolbar.displayProgress](../../mozilla.components.concept.toolbar/-toolbar/display-progress.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-site-security-icon.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-site-security-icon.md index bf75bf02ee3..1f27ac84e6a 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-site-security-icon.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-site-security-icon.md @@ -2,7 +2,7 @@ # displaySiteSecurityIcon -`var displaySiteSecurityIcon: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L109) +`var displaySiteSecurityIcon: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L110) Set/Get whether a site security icon (usually a lock or globe icon) should be visible next to the URL. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-tracking-protection-icon.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-tracking-protection-icon.md index 2830b414455..f76521f4885 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-tracking-protection-icon.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/display-tracking-protection-icon.md @@ -2,7 +2,7 @@ # displayTrackingProtectionIcon -`var displayTrackingProtectionIcon: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L421) +`var displayTrackingProtectionIcon: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L427) Set/Get whether a tracking protection icon (usually a shield icon) should be visible. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/edit-mode.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/edit-mode.md index e841f443057..49b8cf266d4 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/edit-mode.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/edit-mode.md @@ -2,7 +2,7 @@ # editMode -`fun editMode(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L613) +`fun editMode(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L624) Overrides [Toolbar.editMode](../../mozilla.components.concept.toolbar/-toolbar/edit-mode.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/focus.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/focus.md index 76826af80ff..6a2f75634a3 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/focus.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/focus.md @@ -2,7 +2,7 @@ # focus -`fun focus(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L606) +`fun focus(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L617) Focuses the editToolbar if already in edit mode diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint-color.md index f77d196daaf..d7a53d79547 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint-color.md @@ -2,7 +2,7 @@ # hintColor -`var hintColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L180) +`var hintColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L181) Sets the colour of the text to be displayed when the URL of the toolbar is empty. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint.md index e34167f270b..5d2a1d1b713 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/hint.md @@ -2,7 +2,7 @@ # hint -`var hint: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L170) +`var hint: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L171) Sets the text to be displayed when the URL of the toolbar is empty. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/index.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/index.md index cf874923bf3..8cda1bc4255 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/index.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/index.md @@ -2,7 +2,7 @@ # BrowserToolbar -`class BrowserToolbar : `[`Toolbar`](../../mozilla.components.concept.toolbar/-toolbar/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L69) +`class BrowserToolbar : `[`Toolbar`](../../mozilla.components.concept.toolbar/-toolbar/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L70) A customizable toolbar for browsers. @@ -52,7 +52,7 @@ implemented by the DisplayToolbar and EditToolbar classes. | [progressBarGravity](progress-bar-gravity.md) | `var progressBarGravity: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)
Set progress bar to be at the top of the toolbar. It's on bottom by default. | | [separatorColor](separator-color.md) | `var separatorColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)
Sets the colour of the vertical separator between the tracking protection icon and the security indicator icon. | | [siteSecure](site-secure.md) | `var siteSecure: `[`SiteSecurity`](../../mozilla.components.concept.toolbar/-toolbar/-site-security/index.md)
Sets/Gets the site security to be displayed on the toolbar. | -| [siteSecurityColor](site-security-color.md) | `var siteSecurityColor: `[`Pair`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/index.html)`<`[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`>`
Set/Get the site security icon colours (usually a lock or globe icon). It uses a pair of integers which represent the insecure and secure colours respectively. | +| [siteSecurityIcons](site-security-icons.md) | `var siteSecurityIcons: `[`SiteSecurityIcons`](../../mozilla.components.browser.toolbar.display/-site-security-icons/index.md)
Set/Get the site security icons (usually a lock or globe icon). It uses a pair of drawables which represent the insecure and secure colours respectively. | | [siteTrackingProtection](site-tracking-protection.md) | `var siteTrackingProtection: `[`SiteTrackingProtection`](../../mozilla.components.concept.toolbar/-toolbar/-site-tracking-protection/index.md)
Sets/Gets the site tracking protection state to be displayed on the toolbar. | | [suggestionBackgroundColor](suggestion-background-color.md) | `var suggestionBackgroundColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)
The background color used for autocomplete suggestions in edit mode. | | [suggestionForegroundColor](suggestion-foreground-color.md) | `var suggestionForegroundColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`?`
The foreground color used for autocomplete suggestions in edit mode. | @@ -91,6 +91,7 @@ implemented by the DisplayToolbar and EditToolbar classes. | [setOnUrlCommitListener](set-on-url-commit-listener.md) | `fun setOnUrlCommitListener(listener: (`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`) -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
Registers the given function to be invoked when the user selected a new URL i.e. is done editing. | | [setOnUrlLongClickListener](set-on-url-long-click-listener.md) | `fun setOnUrlLongClickListener(handler: () -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
Set a LongClickListener to the urlView of the toolbar. | | [setSearchTerms](set-search-terms.md) | `fun setSearchTerms(searchTerms: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
Displays the currently used search terms as part of this Toolbar. | +| [setSiteSecurityColor](set-site-security-color.md) | `fun setSiteSecurityColor(colors: `[`Pair`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/index.html)`<`[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`>): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | | [setTrackingProtectionIcons](set-tracking-protection-icons.md) | `fun setTrackingProtectionIcons(iconOnNoTrackersBlocked: = requireNotNull( context.getDrawable( TrackingProtectionIconView.DEFAULT_ICON_ON_NO_TRACKERS_BLOCKED diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/invalidate-actions.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/invalidate-actions.md index b086440e9a7..880aad65175 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/invalidate-actions.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/invalidate-actions.md @@ -2,7 +2,7 @@ # invalidateActions -`fun invalidateActions(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L559) +`fun invalidateActions(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L570) Declare that the actions (navigation actions, browser actions, page actions) have changed and should be updated if needed. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/menu-view-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/menu-view-color.md index 1c97ef4d4e3..38f0b21ac81 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/menu-view-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/menu-view-color.md @@ -2,7 +2,7 @@ # menuViewColor -`var menuViewColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L133) +`var menuViewColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L134) Gets/Sets the color tint of the menu button. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-back-pressed.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-back-pressed.md index 20283880a2d..64ef3b77096 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-back-pressed.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-back-pressed.md @@ -2,7 +2,7 @@ # onBackPressed -`fun onBackPressed(): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L531) +`fun onBackPressed(): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L542) Overrides [Toolbar.onBackPressed](../../mozilla.components.concept.toolbar/-toolbar/on-back-pressed.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-layout.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-layout.md index 157bfcaa7d9..5a68f22509e 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-layout.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-layout.md @@ -2,4 +2,4 @@ # onLayout -`fun onLayout(changed: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`, left: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, top: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, right: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, bottom: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L498) \ No newline at end of file +`fun onLayout(changed: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`, left: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, top: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, right: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, bottom: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L509) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-measure.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-measure.md index 346a6f659ac..93b7d95a337 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-measure.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-measure.md @@ -2,4 +2,4 @@ # onMeasure -`fun onMeasure(widthMeasureSpec: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, heightMeasureSpec: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L509) \ No newline at end of file +`fun onMeasure(widthMeasureSpec: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, heightMeasureSpec: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L520) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-url-clicked.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-url-clicked.md index f63cf3101e8..390695639cd 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-url-clicked.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/on-url-clicked.md @@ -2,7 +2,7 @@ # onUrlClicked -`var onUrlClicked: () -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L163) +`var onUrlClicked: () -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L164) Sets a lambda that will be invoked whenever the URL in display mode was clicked. Only if this lambda returns true the toolbar will switch to editing mode. Return diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/private.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/private.md index fe14d12f2d2..47f5af0425e 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/private.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/private.md @@ -2,7 +2,7 @@ # private -`var private: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L96) +`var private: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L97) Overrides [Toolbar.private](../../mozilla.components.concept.toolbar/-toolbar/private.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/progress-bar-gravity.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/progress-bar-gravity.md index 186e48b02ab..455b6fdcb7e 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/progress-bar-gravity.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/progress-bar-gravity.md @@ -2,7 +2,7 @@ # progressBarGravity -`var progressBarGravity: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L190) +`var progressBarGravity: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L191) Set progress bar to be at the top of the toolbar. It's on bottom by default. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/separator-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/separator-color.md index 97823510a4c..f58910a4121 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/separator-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/separator-color.md @@ -2,7 +2,7 @@ # separatorColor -`var separatorColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L254) +`var separatorColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L255) Sets the colour of the vertical separator between the tracking protection icon and the security indicator icon. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-autocomplete-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-autocomplete-listener.md index 476ca1ddb9b..227795c8f56 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-autocomplete-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-autocomplete-listener.md @@ -2,7 +2,7 @@ # setAutocompleteListener -`fun setAutocompleteListener(filter: suspend (`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, `[`AutocompleteDelegate`](../../mozilla.components.concept.toolbar/-autocomplete-delegate/index.md)`) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L362) +`fun setAutocompleteListener(filter: suspend (`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, `[`AutocompleteDelegate`](../../mozilla.components.concept.toolbar/-autocomplete-delegate/index.md)`) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L368) Overrides [Toolbar.setAutocompleteListener](../../mozilla.components.concept.toolbar/-toolbar/set-autocomplete-listener.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-menu-builder.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-menu-builder.md index 8add3f2c97f..6f5e1e03dbf 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-menu-builder.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-menu-builder.md @@ -2,7 +2,7 @@ # setMenuBuilder -`fun setMenuBuilder(menuBuilder: `[`BrowserMenuBuilder`](../../mozilla.components.browser.menu/-browser-menu-builder/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L635) +`fun setMenuBuilder(menuBuilder: `[`BrowserMenuBuilder`](../../mozilla.components.browser.menu/-browser-menu-builder/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L646) Sets a BrowserMenuBuilder that will be used to create a menu when the menu button is clicked. The menu button will only be visible if a builder has been set. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-focus-change-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-focus-change-listener.md index 396c7820fc0..1c706c4bbfe 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-focus-change-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-focus-change-listener.md @@ -2,7 +2,7 @@ # setOnEditFocusChangeListener -`fun setOnEditFocusChangeListener(listener: (`[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L306) +`fun setOnEditFocusChangeListener(listener: (`[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L312) Sets a listener to be invoked when focus of the URL input view (in edit mode) changed. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-listener.md index 20181b05d68..ecc877bfb51 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-edit-listener.md @@ -2,7 +2,7 @@ # setOnEditListener -`fun setOnEditListener(listener: `[`OnEditListener`](../../mozilla.components.concept.toolbar/-toolbar/-on-edit-listener/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L358) +`fun setOnEditListener(listener: `[`OnEditListener`](../../mozilla.components.concept.toolbar/-toolbar/-on-edit-listener/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L364) Overrides [Toolbar.setOnEditListener](../../mozilla.components.concept.toolbar/-toolbar/set-on-edit-listener.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-site-security-clicked-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-site-security-clicked-listener.md index 17488115c06..f8d436408ac 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-site-security-clicked-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-site-security-clicked-listener.md @@ -2,7 +2,7 @@ # setOnSiteSecurityClickedListener -`fun setOnSiteSecurityClickedListener(listener: () -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L315) +`fun setOnSiteSecurityClickedListener(listener: () -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L321) Sets a listener to be invoked when the site security indicator icon is clicked. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-tracking-protection-clicked-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-tracking-protection-clicked-listener.md index 053e4069a95..a33aa58f3e9 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-tracking-protection-clicked-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-tracking-protection-clicked-listener.md @@ -2,7 +2,7 @@ # setOnTrackingProtectionClickedListener -`fun setOnTrackingProtectionClickedListener(listener: () -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L338) +`fun setOnTrackingProtectionClickedListener(listener: () -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L344) Sets a listener to be invoked when the site tracking protection indicator icon is clicked. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-commit-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-commit-listener.md index 6c48a784702..80bad356c73 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-commit-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-commit-listener.md @@ -2,7 +2,7 @@ # setOnUrlCommitListener -`fun setOnUrlCommitListener(listener: (`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`) -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L547) +`fun setOnUrlCommitListener(listener: (`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`) -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L558) Overrides [Toolbar.setOnUrlCommitListener](../../mozilla.components.concept.toolbar/-toolbar/set-on-url-commit-listener.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-long-click-listener.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-long-click-listener.md index 72e170f409f..98b688a3f72 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-long-click-listener.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-on-url-long-click-listener.md @@ -2,7 +2,7 @@ # setOnUrlLongClickListener -`fun setOnUrlLongClickListener(handler: () -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L642) +`fun setOnUrlLongClickListener(handler: () -> `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L653) Set a LongClickListener to the urlView of the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-search-terms.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-search-terms.md index e682fee7d3f..f10fbff5420 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-search-terms.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-search-terms.md @@ -2,7 +2,7 @@ # setSearchTerms -`fun setSearchTerms(searchTerms: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L539) +`fun setSearchTerms(searchTerms: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L550) Overrides [Toolbar.setSearchTerms](../../mozilla.components.concept.toolbar/-toolbar/set-search-terms.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-site-security-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-site-security-color.md new file mode 100644 index 00000000000..a98fde7bbe4 --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-site-security-color.md @@ -0,0 +1,5 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar](../index.md) / [BrowserToolbar](index.md) / [setSiteSecurityColor](./set-site-security-color.md) + +# setSiteSecurityColor + +`fun setSiteSecurityColor(colors: `[`Pair`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/index.html)`<`[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`>): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L304) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-tracking-protection-icons.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-tracking-protection-icons.md index f14a1b9080f..9fa343586cd 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-tracking-protection-icons.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-tracking-protection-icons.md @@ -14,7 +14,7 @@ context.getDrawable( TrackingProtectionIconView.DEFAULT_ICON_OFF_FOR_A_SITE ) - )): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L225) + )): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L226) Sets the different icons that the tracking protection icon could has depending of its [Toolbar.siteTrackingProtection](../../mozilla.components.concept.toolbar/-toolbar/site-tracking-protection.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-url-text-padding.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-url-text-padding.md index 070124df37e..cd57831a763 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-url-text-padding.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/set-url-text-padding.md @@ -2,7 +2,7 @@ # setUrlTextPadding -`fun setUrlTextPadding(left: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingLeft, top: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingTop, right: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingRight, bottom: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingBottom): ` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L375) +`fun setUrlTextPadding(left: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingLeft, top: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingTop, right: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingRight, bottom: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = displayToolbar.urlView.paddingBottom): ` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L381) Sets the padding to be applied to the URL text (in display mode). diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-secure.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-secure.md index 0a07f5c7819..cd6864dee9c 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-secure.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-secure.md @@ -2,7 +2,7 @@ # siteSecure -`var siteSecure: `[`SiteSecurity`](../../mozilla.components.concept.toolbar/-toolbar/-site-security/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L403) +`var siteSecure: `[`SiteSecurity`](../../mozilla.components.concept.toolbar/-toolbar/-site-security/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L409) Overrides [Toolbar.siteSecure](../../mozilla.components.concept.toolbar/-toolbar/site-secure.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-color.md deleted file mode 100644 index 745609abe54..00000000000 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-color.md +++ /dev/null @@ -1,9 +0,0 @@ -[android-components](../../index.md) / [mozilla.components.browser.toolbar](../index.md) / [BrowserToolbar](index.md) / [siteSecurityColor](./site-security-color.md) - -# siteSecurityColor - -`var siteSecurityColor: `[`Pair`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/index.html)`<`[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`, `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`>` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L119) - -Set/Get the site security icon colours (usually a lock or globe icon). It uses a pair of integers -which represent the insecure and secure colours respectively. - diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-icons.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-icons.md new file mode 100644 index 00000000000..4c0ef8c9724 --- /dev/null +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-security-icons.md @@ -0,0 +1,9 @@ +[android-components](../../index.md) / [mozilla.components.browser.toolbar](../index.md) / [BrowserToolbar](index.md) / [siteSecurityIcons](./site-security-icons.md) + +# siteSecurityIcons + +`var siteSecurityIcons: `[`SiteSecurityIcons`](../../mozilla.components.browser.toolbar.display/-site-security-icons/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L120) + +Set/Get the site security icons (usually a lock or globe icon). It uses a pair of drawables +which represent the insecure and secure colours respectively. + diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-tracking-protection.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-tracking-protection.md index c662982c672..b309042633e 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-tracking-protection.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/site-tracking-protection.md @@ -2,7 +2,7 @@ # siteTrackingProtection -`var siteTrackingProtection: `[`SiteTrackingProtection`](../../mozilla.components.concept.toolbar/-toolbar/-site-tracking-protection/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L409) +`var siteTrackingProtection: `[`SiteTrackingProtection`](../../mozilla.components.concept.toolbar/-toolbar/-site-tracking-protection/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L415) Overrides [Toolbar.siteTrackingProtection](../../mozilla.components.concept.toolbar/-toolbar/site-tracking-protection.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-background-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-background-color.md index d4595f8afe3..8610c7e1331 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-background-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-background-color.md @@ -2,7 +2,7 @@ # suggestionBackgroundColor -`var suggestionBackgroundColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L282) +`var suggestionBackgroundColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L283) The background color used for autocomplete suggestions in edit mode. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-foreground-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-foreground-color.md index 694efa80a3d..e196fe58b27 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-foreground-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/suggestion-foreground-color.md @@ -2,7 +2,7 @@ # suggestionForegroundColor -`var suggestionForegroundColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L289) +`var suggestionForegroundColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L290) The foreground color used for autocomplete suggestions in edit mode. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-color.md index e7fbdd82e86..8b525817bf0 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-color.md @@ -2,7 +2,7 @@ # textColor -`var textColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L208) +`var textColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L209) Sets the colour of the text for the URL/search term displayed in the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-size.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-size.md index 3405d1e5546..e008eadc86e 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-size.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/text-size.md @@ -2,7 +2,7 @@ # textSize -`var textSize: `[`Float`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L272) +`var textSize: `[`Float`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L273) Sets the size of the text for the URL/search term displayed in the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-color.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-color.md index c2e4084cc0e..cac3ef0e527 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-color.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-color.md @@ -2,7 +2,7 @@ # titleColor -`var titleColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L199) +`var titleColor: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L200) Sets the colour of the text for title displayed in the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-text-size.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-text-size.md index 90e9b28eff0..128570b1487 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-text-size.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title-text-size.md @@ -2,7 +2,7 @@ # titleTextSize -`var titleTextSize: `[`Float`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L263) +`var titleTextSize: `[`Float`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L264) Sets the size of the text for the title displayed in the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title.md index e685607e86c..9fd29b396d7 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/title.md @@ -2,7 +2,7 @@ # title -`var title: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L386) +`var title: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L392) Overrides [Toolbar.title](../../mozilla.components.concept.toolbar/-toolbar/title.md) diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/typeface.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/typeface.md index df199081dcf..31ea57eeeeb 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/typeface.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/typeface.md @@ -2,7 +2,7 @@ # typeface -`var typeface: ` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L296) +`var typeface: ` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L297) Sets the typeface of the text for the URL/search term displayed in the toolbar. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-margin.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-margin.md index 6d7478ec6bc..903399b1a4f 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-margin.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-margin.md @@ -2,7 +2,7 @@ # urlBoxMargin -`var urlBoxMargin: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L154) +`var urlBoxMargin: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L155) Gets/Sets horizontal margin of the URL box (surrounding URL and page actions) in display mode. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-view.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-view.md index 2cdf7beaac5..69cb8890428 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-view.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url-box-view.md @@ -2,7 +2,7 @@ # urlBoxView -`var urlBoxView: ?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L126) +`var urlBoxView: ?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L127) Gets/Sets a custom view that will be drawn as behind the URL and page actions in display mode. diff --git a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url.md b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url.md index 06f54d8a469..a027fde6f1e 100644 --- a/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url.md +++ b/docs/api/mozilla.components.browser.toolbar/-browser-toolbar/url.md @@ -2,7 +2,7 @@ # url -`var url: `[`CharSequence`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-char-sequence/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L393) +`var url: `[`CharSequence`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-char-sequence/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt#L399) Overrides [Toolbar.url](../../mozilla.components.concept.toolbar/-toolbar/url.md) diff --git a/docs/api/mozilla.components.feature.push/-auto-push-feature/force-registration-renewal.md b/docs/api/mozilla.components.feature.push/-auto-push-feature/force-registration-renewal.md index 0e3ee438789..49914d6ded1 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-feature/force-registration-renewal.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-feature/force-registration-renewal.md @@ -2,8 +2,11 @@ # forceRegistrationRenewal -`fun forceRegistrationRenewal(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L235) +`fun forceRegistrationRenewal(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L245) Deletes the registration token locally so that it forces the service to get a new one the next time hits it's messaging server. +Implementation notes: This shouldn't need to be used unless we're certain. When we introduce +[a polling service](https://github.com/mozilla-mobile/android-components/issues/3173) to check if endpoints are expired, we would invoke this. + diff --git a/docs/api/mozilla.components.feature.push/-auto-push-feature/subscribe-all.md b/docs/api/mozilla.components.feature.push/-auto-push-feature/subscribe-all.md index 354ce3b89f4..1d948823283 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-feature/subscribe-all.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-feature/subscribe-all.md @@ -2,7 +2,7 @@ # subscribeAll -`fun subscribeAll(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L220) +`fun subscribeAll(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L225) Returns all subscription for the push type if available. diff --git a/docs/api/mozilla.components.feature.push/-auto-push-feature/unsubscribe-for-type.md b/docs/api/mozilla.components.feature.push/-auto-push-feature/unsubscribe-for-type.md index ae109dd9173..bd4dbf9fa38 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-feature/unsubscribe-for-type.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-feature/unsubscribe-for-type.md @@ -2,7 +2,10 @@ # unsubscribeForType -`fun unsubscribeForType(type: `[`PushType`](../-push-type/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L209) +`fun unsubscribeForType(type: `[`PushType`](../-push-type/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L214) Returns subscription information for the push type if available. +Implementation notes: We need to connect this to the device constellation so that we update our subscriptions +when notified by FxA. See [#3859](https://github.com/mozilla-mobile/android-components/issues/3859). + diff --git a/docs/api/mozilla.components.feature.push/-auto-push-subscription/auth-key.md b/docs/api/mozilla.components.feature.push/-auto-push-subscription/auth-key.md index 4bc45ea6741..22a44cb9eef 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-subscription/auth-key.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-subscription/auth-key.md @@ -2,4 +2,4 @@ # authKey -`val authKey: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L338) \ No newline at end of file +`val authKey: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L348) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-auto-push-subscription/endpoint.md b/docs/api/mozilla.components.feature.push/-auto-push-subscription/endpoint.md index 12e70e3b62b..ee1ff5b3e98 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-subscription/endpoint.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-subscription/endpoint.md @@ -2,4 +2,4 @@ # endpoint -`val endpoint: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L336) \ No newline at end of file +`val endpoint: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L346) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-auto-push-subscription/index.md b/docs/api/mozilla.components.feature.push/-auto-push-subscription/index.md index cdfba743d6d..f77c148fee6 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-subscription/index.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-subscription/index.md @@ -2,7 +2,7 @@ # AutoPushSubscription -`data class AutoPushSubscription` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L334) +`data class AutoPushSubscription` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L344) The subscription information from Autopush that can be used to send push messages to other devices. diff --git a/docs/api/mozilla.components.feature.push/-auto-push-subscription/public-key.md b/docs/api/mozilla.components.feature.push/-auto-push-subscription/public-key.md index 5ee6939d1e6..1caf294b8a5 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-subscription/public-key.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-subscription/public-key.md @@ -2,4 +2,4 @@ # publicKey -`val publicKey: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L337) \ No newline at end of file +`val publicKey: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L347) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-auto-push-subscription/type.md b/docs/api/mozilla.components.feature.push/-auto-push-subscription/type.md index 690ee401e7c..f66f581ca45 100644 --- a/docs/api/mozilla.components.feature.push/-auto-push-subscription/type.md +++ b/docs/api/mozilla.components.feature.push/-auto-push-subscription/type.md @@ -2,4 +2,4 @@ # type -`val type: `[`PushType`](../-push-type/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L335) \ No newline at end of file +`val type: `[`PushType`](../-push-type/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L345) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p-s.md b/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p-s.md index a42d361aa25..d0ab711e02d 100644 --- a/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p-s.md +++ b/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p-s.md @@ -2,4 +2,4 @@ # HTTPS -`HTTPS` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L328) \ No newline at end of file +`HTTPS` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L338) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p.md b/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p.md index a9652239d60..4b4ef78da7f 100644 --- a/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p.md +++ b/docs/api/mozilla.components.feature.push/-protocol/-h-t-t-p.md @@ -2,4 +2,4 @@ # HTTP -`HTTP` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L327) \ No newline at end of file +`HTTP` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L337) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-protocol/index.md b/docs/api/mozilla.components.feature.push/-protocol/index.md index 1df0433ba47..9db7a2f3619 100644 --- a/docs/api/mozilla.components.feature.push/-protocol/index.md +++ b/docs/api/mozilla.components.feature.push/-protocol/index.md @@ -2,7 +2,7 @@ # Protocol -`enum class Protocol` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L326) +`enum class Protocol` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L336) Supported network protocols. diff --git a/docs/api/mozilla.components.feature.push/-push-config/index.md b/docs/api/mozilla.components.feature.push/-push-config/index.md index cb8b49f393a..a4560b79ae2 100644 --- a/docs/api/mozilla.components.feature.push/-push-config/index.md +++ b/docs/api/mozilla.components.feature.push/-push-config/index.md @@ -2,7 +2,7 @@ # PushConfig -`data class PushConfig` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L344) +`data class PushConfig` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L354) Configuration object for initializing the Push Manager. diff --git a/docs/api/mozilla.components.feature.push/-push-config/protocol.md b/docs/api/mozilla.components.feature.push/-push-config/protocol.md index e725b20f2e5..af6a8d2347a 100644 --- a/docs/api/mozilla.components.feature.push/-push-config/protocol.md +++ b/docs/api/mozilla.components.feature.push/-push-config/protocol.md @@ -2,4 +2,4 @@ # protocol -`val protocol: `[`Protocol`](../-protocol/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L347) \ No newline at end of file +`val protocol: `[`Protocol`](../-protocol/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L357) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-push-config/sender-id.md b/docs/api/mozilla.components.feature.push/-push-config/sender-id.md index 60c51318374..411c63d4ac2 100644 --- a/docs/api/mozilla.components.feature.push/-push-config/sender-id.md +++ b/docs/api/mozilla.components.feature.push/-push-config/sender-id.md @@ -2,4 +2,4 @@ # senderId -`val senderId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L345) \ No newline at end of file +`val senderId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L355) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-push-config/server-host.md b/docs/api/mozilla.components.feature.push/-push-config/server-host.md index 94c40aa1591..dec7c626588 100644 --- a/docs/api/mozilla.components.feature.push/-push-config/server-host.md +++ b/docs/api/mozilla.components.feature.push/-push-config/server-host.md @@ -2,4 +2,4 @@ # serverHost -`val serverHost: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L346) \ No newline at end of file +`val serverHost: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L356) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-push-config/service-type.md b/docs/api/mozilla.components.feature.push/-push-config/service-type.md index dd63988fd35..9b43296bbc7 100644 --- a/docs/api/mozilla.components.feature.push/-push-config/service-type.md +++ b/docs/api/mozilla.components.feature.push/-push-config/service-type.md @@ -2,4 +2,4 @@ # serviceType -`val serviceType: `[`ServiceType`](../-service-type/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L348) \ No newline at end of file +`val serviceType: `[`ServiceType`](../-service-type/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L358) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-push-subscription-observer/index.md b/docs/api/mozilla.components.feature.push/-push-subscription-observer/index.md index ca7f161d68f..e33159d3a70 100644 --- a/docs/api/mozilla.components.feature.push/-push-subscription-observer/index.md +++ b/docs/api/mozilla.components.feature.push/-push-subscription-observer/index.md @@ -2,7 +2,7 @@ # PushSubscriptionObserver -`interface PushSubscriptionObserver` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L292) +`interface PushSubscriptionObserver` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L302) Observers that want to receive updates for new subscriptions. diff --git a/docs/api/mozilla.components.feature.push/-push-subscription-observer/on-subscription-available.md b/docs/api/mozilla.components.feature.push/-push-subscription-observer/on-subscription-available.md index 1e5930fa5a3..2335364acb9 100644 --- a/docs/api/mozilla.components.feature.push/-push-subscription-observer/on-subscription-available.md +++ b/docs/api/mozilla.components.feature.push/-push-subscription-observer/on-subscription-available.md @@ -2,4 +2,4 @@ # onSubscriptionAvailable -`abstract fun onSubscriptionAvailable(subscription: `[`AutoPushSubscription`](../-auto-push-subscription/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L293) \ No newline at end of file +`abstract fun onSubscriptionAvailable(subscription: `[`AutoPushSubscription`](../-auto-push-subscription/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L303) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-push-type/-services.md b/docs/api/mozilla.components.feature.push/-push-type/-services.md index cf804a2b3f0..64a7b364f73 100644 --- a/docs/api/mozilla.components.feature.push/-push-type/-services.md +++ b/docs/api/mozilla.components.feature.push/-push-type/-services.md @@ -2,7 +2,7 @@ # Services -`Services` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L278) +`Services` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L288) ### Inherited Functions diff --git a/docs/api/mozilla.components.feature.push/-push-type/-web-push.md b/docs/api/mozilla.components.feature.push/-push-type/-web-push.md index e5ecead06de..174b55c429b 100644 --- a/docs/api/mozilla.components.feature.push/-push-type/-web-push.md +++ b/docs/api/mozilla.components.feature.push/-push-type/-web-push.md @@ -2,7 +2,7 @@ # WebPush -`WebPush` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L279) +`WebPush` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L289) ### Inherited Functions diff --git a/docs/api/mozilla.components.feature.push/-push-type/index.md b/docs/api/mozilla.components.feature.push/-push-type/index.md index e22149ce40a..9da70acd462 100644 --- a/docs/api/mozilla.components.feature.push/-push-type/index.md +++ b/docs/api/mozilla.components.feature.push/-push-type/index.md @@ -2,7 +2,7 @@ # PushType -`enum class PushType` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L277) +`enum class PushType` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L287) The different kind of message types that a [EncryptedPushMessage](../../mozilla.components.concept.push/-encrypted-push-message/index.md) can be: diff --git a/docs/api/mozilla.components.feature.push/-push-type/to-channel-id.md b/docs/api/mozilla.components.feature.push/-push-type/to-channel-id.md index 051fd12d749..11d9ac8f4e0 100644 --- a/docs/api/mozilla.components.feature.push/-push-type/to-channel-id.md +++ b/docs/api/mozilla.components.feature.push/-push-type/to-channel-id.md @@ -2,7 +2,7 @@ # toChannelId -`fun toChannelId(): `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L286) +`fun toChannelId(): `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L296) Retrieve a channel ID from the PushType. diff --git a/docs/api/mozilla.components.feature.push/-service-type/-a-d-m.md b/docs/api/mozilla.components.feature.push/-service-type/-a-d-m.md index 159b38cc011..50a4bf8dbcc 100644 --- a/docs/api/mozilla.components.feature.push/-service-type/-a-d-m.md +++ b/docs/api/mozilla.components.feature.push/-service-type/-a-d-m.md @@ -2,4 +2,4 @@ # ADM -`ADM` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L320) \ No newline at end of file +`ADM` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L330) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-service-type/-f-c-m.md b/docs/api/mozilla.components.feature.push/-service-type/-f-c-m.md index 90d38f61478..6d46fde740c 100644 --- a/docs/api/mozilla.components.feature.push/-service-type/-f-c-m.md +++ b/docs/api/mozilla.components.feature.push/-service-type/-f-c-m.md @@ -2,4 +2,4 @@ # FCM -`FCM` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L319) \ No newline at end of file +`FCM` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L329) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.push/-service-type/index.md b/docs/api/mozilla.components.feature.push/-service-type/index.md index 416f620f85b..c4f34ad80d6 100644 --- a/docs/api/mozilla.components.feature.push/-service-type/index.md +++ b/docs/api/mozilla.components.feature.push/-service-type/index.md @@ -2,7 +2,7 @@ # ServiceType -`enum class ServiceType` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L318) +`enum class ServiceType` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/push/src/main/java/mozilla/components/feature/push/AutoPushFeature.kt#L328) Supported push services. diff --git a/docs/api/mozilla.components.feature.sendtab/-send-tab-feature/-init-.md b/docs/api/mozilla.components.feature.sendtab/-send-tab-feature/-init-.md new file mode 100644 index 00000000000..a307c34c756 --- /dev/null +++ b/docs/api/mozilla.components.feature.sendtab/-send-tab-feature/-init-.md @@ -0,0 +1,25 @@ +[android-components](../../index.md) / [mozilla.components.feature.sendtab](../index.md) / [SendTabFeature](index.md) / [<init>](./-init-.md) + +# <init> + +`SendTabFeature(accountManager: `[`FxaAccountManager`](../../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md)`, pushFeature: `[`AutoPushFeature`](../../mozilla.components.feature.push/-auto-push-feature/index.md)`? = null, owner: LifecycleOwner = ProcessLifecycleOwner.get(), autoPause: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false, onTabsReceived: (`[`Device`](../../mozilla.components.concept.sync/-device/index.md)`?, `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`TabData`](../../mozilla.components.concept.sync/-tab-data/index.md)`>) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`)` + +A feature that uses the [FxaAccountManager](../../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md) to send and receive tabs with optional push support +for receiving tabs from the [AutoPushFeature](../../mozilla.components.feature.push/-auto-push-feature/index.md) and a [PushService](../../mozilla.components.concept.push/-push-service/index.md). + +If the push components are not used, the feature can still function while tabs would only be +received when refreshing the device state. + +### Parameters + +`accountManager` - Firefox account manager. + +`pushFeature` - The [AutoPushFeature](../../mozilla.components.feature.push/-auto-push-feature/index.md) if that is setup for observing push events. + +`owner` - Android lifecycle owner for the observers. Defaults to the [ProcessLifecycleOwner](#) +so that we can always observe events throughout the application lifecycle. + +`autoPause` - whether or not the observer should automatically be +paused/resumed with the bound lifecycle. + +`onTabsReceived` - the callback invoked with new tab(s) are received. \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.sendtab/-send-tab-feature/index.md b/docs/api/mozilla.components.feature.sendtab/-send-tab-feature/index.md new file mode 100644 index 00000000000..17a00dcf838 --- /dev/null +++ b/docs/api/mozilla.components.feature.sendtab/-send-tab-feature/index.md @@ -0,0 +1,31 @@ +[android-components](../../index.md) / [mozilla.components.feature.sendtab](../index.md) / [SendTabFeature](./index.md) + +# SendTabFeature + +`class SendTabFeature` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/sendtab/src/main/java/mozilla/components/feature/sendtab/SendTabFeature.kt#L43) + +A feature that uses the [FxaAccountManager](../../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md) to send and receive tabs with optional push support +for receiving tabs from the [AutoPushFeature](../../mozilla.components.feature.push/-auto-push-feature/index.md) and a [PushService](../../mozilla.components.concept.push/-push-service/index.md). + +If the push components are not used, the feature can still function while tabs would only be +received when refreshing the device state. + +### Parameters + +`accountManager` - Firefox account manager. + +`pushFeature` - The [AutoPushFeature](../../mozilla.components.feature.push/-auto-push-feature/index.md) if that is setup for observing push events. + +`owner` - Android lifecycle owner for the observers. Defaults to the [ProcessLifecycleOwner](#) +so that we can always observe events throughout the application lifecycle. + +`autoPause` - whether or not the observer should automatically be +paused/resumed with the bound lifecycle. + +`onTabsReceived` - the callback invoked with new tab(s) are received. + +### Constructors + +| Name | Summary | +|---|---| +| [<init>](-init-.md) | `SendTabFeature(accountManager: `[`FxaAccountManager`](../../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md)`, pushFeature: `[`AutoPushFeature`](../../mozilla.components.feature.push/-auto-push-feature/index.md)`? = null, owner: LifecycleOwner = ProcessLifecycleOwner.get(), autoPause: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false, onTabsReceived: (`[`Device`](../../mozilla.components.concept.sync/-device/index.md)`?, `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`TabData`](../../mozilla.components.concept.sync/-tab-data/index.md)`>) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`)`
A feature that uses the [FxaAccountManager](../../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md) to send and receive tabs with optional push support for receiving tabs from the [AutoPushFeature](../../mozilla.components.feature.push/-auto-push-feature/index.md) and a [PushService](../../mozilla.components.concept.push/-push-service/index.md). | diff --git a/docs/api/mozilla.components.feature.sendtab/index.md b/docs/api/mozilla.components.feature.sendtab/index.md index 710f5a16229..30563b6c00c 100644 --- a/docs/api/mozilla.components.feature.sendtab/index.md +++ b/docs/api/mozilla.components.feature.sendtab/index.md @@ -6,4 +6,5 @@ | Name | Summary | |---|---| +| [SendTabFeature](-send-tab-feature/index.md) | `class SendTabFeature`
A feature that uses the [FxaAccountManager](../mozilla.components.service.fxa.manager/-fxa-account-manager/index.md) to send and receive tabs with optional push support for receiving tabs from the [AutoPushFeature](../mozilla.components.feature.push/-auto-push-feature/index.md) and a [PushService](../mozilla.components.concept.push/-push-service/index.md). | | [SendTabUseCases](-send-tab-use-cases/index.md) | `class SendTabUseCases`
Contains use cases for sending tabs to devices related to the firefox-accounts. | diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-c-o-n-n-e-c-t-i-o-n_-t-i-m-e-o-u-t.md b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-c-o-n-n-e-c-t-i-o-n_-t-i-m-e-o-u-t.md index bb3875988b1..82d6822ee87 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-c-o-n-n-e-c-t-i-o-n_-t-i-m-e-o-u-t.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-c-o-n-n-e-c-t-i-o-n_-t-i-m-e-o-u-t.md @@ -2,4 +2,4 @@ # DEFAULT_CONNECTION_TIMEOUT -`const val DEFAULT_CONNECTION_TIMEOUT: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L69) \ No newline at end of file +`const val DEFAULT_CONNECTION_TIMEOUT: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L70) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-l-o-g_-p-i-n-g-s.md b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-l-o-g_-p-i-n-g-s.md index bda9de6a625..0f0ba82c8c1 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-l-o-g_-p-i-n-g-s.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-l-o-g_-p-i-n-g-s.md @@ -2,4 +2,4 @@ # DEFAULT_LOG_PINGS -`const val DEFAULT_LOG_PINGS: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L72) \ No newline at end of file +`const val DEFAULT_LOG_PINGS: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L73) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-m-a-x_-e-v-e-n-t-s.md b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-m-a-x_-e-v-e-n-t-s.md index 8c77755717e..5388864a37d 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-m-a-x_-e-v-e-n-t-s.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-m-a-x_-e-v-e-n-t-s.md @@ -2,4 +2,4 @@ # DEFAULT_MAX_EVENTS -`const val DEFAULT_MAX_EVENTS: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L71) \ No newline at end of file +`const val DEFAULT_MAX_EVENTS: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L72) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-r-e-a-d_-t-i-m-e-o-u-t.md b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-r-e-a-d_-t-i-m-e-o-u-t.md index 96a2ca7d047..7df824bdf2c 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-r-e-a-d_-t-i-m-e-o-u-t.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-r-e-a-d_-t-i-m-e-o-u-t.md @@ -2,4 +2,4 @@ # DEFAULT_READ_TIMEOUT -`const val DEFAULT_READ_TIMEOUT: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L70) \ No newline at end of file +`const val DEFAULT_READ_TIMEOUT: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L71) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-t-e-l-e-m-e-t-r-y_-e-n-d-p-o-i-n-t.md b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-t-e-l-e-m-e-t-r-y_-e-n-d-p-o-i-n-t.md index b3618853f75..2a294cd04ec 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-t-e-l-e-m-e-t-r-y_-e-n-d-p-o-i-n-t.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-t-e-l-e-m-e-t-r-y_-e-n-d-p-o-i-n-t.md @@ -2,4 +2,4 @@ # DEFAULT_TELEMETRY_ENDPOINT -`const val DEFAULT_TELEMETRY_ENDPOINT: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L67) \ No newline at end of file +`const val DEFAULT_TELEMETRY_ENDPOINT: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L68) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-u-s-e-r_-a-g-e-n-t.md b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-u-s-e-r_-a-g-e-n-t.md index 72e030101b8..f4daf7e2a55 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-u-s-e-r_-a-g-e-n-t.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-d-e-f-a-u-l-t_-u-s-e-r_-a-g-e-n-t.md @@ -2,4 +2,4 @@ # DEFAULT_USER_AGENT -`const val DEFAULT_USER_AGENT: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L68) \ No newline at end of file +`const val DEFAULT_USER_AGENT: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/config/Configuration.kt#L69) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/-init-.md b/docs/api/mozilla.components.service.glean.config/-configuration/-init-.md index c1ffd658b85..8a44e8d1698 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/-init-.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/-init-.md @@ -2,4 +2,4 @@ # <init> -`Configuration(connectionTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_CONNECTION_TIMEOUT, readTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_READ_TIMEOUT, maxEvents: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = DEFAULT_MAX_EVENTS, httpClient: `[`Lazy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-lazy/index.html)`<`[`Client`](../../mozilla.components.concept.fetch/-client/index.md)`> = lazy { HttpURLConnectionClient() }, channel: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`? = null)` \ No newline at end of file +`Configuration(serverEndpoint: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)` = DEFAULT_TELEMETRY_ENDPOINT, connectionTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_CONNECTION_TIMEOUT, readTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_READ_TIMEOUT, maxEvents: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = DEFAULT_MAX_EVENTS, httpClient: `[`Lazy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-lazy/index.html)`<`[`Client`](../../mozilla.components.concept.fetch/-client/index.md)`> = lazy { HttpURLConnectionClient() }, channel: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`? = null)` \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.config/-configuration/index.md b/docs/api/mozilla.components.service.glean.config/-configuration/index.md index 380dc6ccdd0..f0ba2efc901 100644 --- a/docs/api/mozilla.components.service.glean.config/-configuration/index.md +++ b/docs/api/mozilla.components.service.glean.config/-configuration/index.md @@ -10,7 +10,7 @@ The Configuration class describes how to configure the Glean. | Name | Summary | |---|---| -| [<init>](-init-.md) | `Configuration(connectionTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_CONNECTION_TIMEOUT, readTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_READ_TIMEOUT, maxEvents: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = DEFAULT_MAX_EVENTS, httpClient: `[`Lazy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-lazy/index.html)`<`[`Client`](../../mozilla.components.concept.fetch/-client/index.md)`> = lazy { HttpURLConnectionClient() }, channel: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`? = null)` | +| [<init>](-init-.md) | `Configuration(serverEndpoint: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)` = DEFAULT_TELEMETRY_ENDPOINT, connectionTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_CONNECTION_TIMEOUT, readTimeout: `[`Long`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)` = DEFAULT_READ_TIMEOUT, maxEvents: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)` = DEFAULT_MAX_EVENTS, httpClient: `[`Lazy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-lazy/index.html)`<`[`Client`](../../mozilla.components.concept.fetch/-client/index.md)`> = lazy { HttpURLConnectionClient() }, channel: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`? = null)` | ### Properties diff --git a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/-init-.md b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/-init-.md index 3c1921bb288..35379caef29 100644 --- a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/-init-.md +++ b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/-init-.md @@ -2,7 +2,7 @@ # <init> -`GleanTestRule(context: )` +`GleanTestRule(context: , configToUse: `[`Configuration`](../../mozilla.components.service.glean.config/-configuration/index.md)` = Configuration())` This implements a JUnit rule for writing tests for Glean SDK metrics. @@ -17,3 +17,8 @@ Example usage: val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) ``` +### Parameters + +`context` - the application context + +`configToUse` - an optional [Configuration](../../mozilla.components.service.glean.config/-configuration/index.md) to initialize the Glean SDK with \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/config-to-use.md b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/config-to-use.md new file mode 100644 index 00000000000..613d55b011c --- /dev/null +++ b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/config-to-use.md @@ -0,0 +1,8 @@ +[android-components](../../index.md) / [mozilla.components.service.glean.testing](../index.md) / [GleanTestRule](index.md) / [configToUse](./config-to-use.md) + +# configToUse + +`val configToUse: `[`Configuration`](../../mozilla.components.service.glean.config/-configuration/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L35) + +an optional [Configuration](../../mozilla.components.service.glean.config/-configuration/index.md) to initialize the Glean SDK with + diff --git a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/context.md b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/context.md index 9a775695b5a..5aa0e264a05 100644 --- a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/context.md +++ b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/context.md @@ -2,4 +2,7 @@ # context -`val context: ` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L31) \ No newline at end of file +`val context: ` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L34) + +the application context + diff --git a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/index.md b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/index.md index 5dba8754cf9..3faae5ed219 100644 --- a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/index.md +++ b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/index.md @@ -2,7 +2,7 @@ # GleanTestRule -`class GleanTestRule : TestWatcher` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L30) +`class GleanTestRule : TestWatcher` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L33) This implements a JUnit rule for writing tests for Glean SDK metrics. @@ -17,17 +17,24 @@ Example usage: val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) ``` +### Parameters + +`context` - the application context + +`configToUse` - an optional [Configuration](../../mozilla.components.service.glean.config/-configuration/index.md) to initialize the Glean SDK with + ### Constructors | Name | Summary | |---|---| -| [<init>](-init-.md) | `GleanTestRule(context: )`
This implements a JUnit rule for writing tests for Glean SDK metrics. | +| [<init>](-init-.md) | `GleanTestRule(context: , configToUse: `[`Configuration`](../../mozilla.components.service.glean.config/-configuration/index.md)` = Configuration())`
This implements a JUnit rule for writing tests for Glean SDK metrics. | ### Properties | Name | Summary | |---|---| -| [context](context.md) | `val context: ` | +| [configToUse](config-to-use.md) | `val configToUse: `[`Configuration`](../../mozilla.components.service.glean.config/-configuration/index.md)
an optional [Configuration](../../mozilla.components.service.glean.config/-configuration/index.md) to initialize the Glean SDK with | +| [context](context.md) | `val context: `
the application context | ### Functions diff --git a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/starting.md b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/starting.md index 86e9bfcf8e1..192e7577533 100644 --- a/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/starting.md +++ b/docs/api/mozilla.components.service.glean.testing/-glean-test-rule/starting.md @@ -2,4 +2,4 @@ # starting -`protected fun starting(description: Description?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L33) \ No newline at end of file +`protected fun starting(description: Description?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/testing/GleanTestRule.kt#L37) \ No newline at end of file diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/get-upload-enabled.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/get-upload-enabled.md index e6f1782d042..651b969c7fc 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/get-upload-enabled.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/get-upload-enabled.md @@ -2,7 +2,7 @@ # getUploadEnabled -`fun getUploadEnabled(): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L192) +`fun getUploadEnabled(): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L194) Get whether or not Glean is allowed to record and upload data. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/handle-background-event.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/handle-background-event.md index 4c52a15be1d..1418834a65a 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/handle-background-event.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/handle-background-event.md @@ -2,7 +2,7 @@ # handleBackgroundEvent -`fun handleBackgroundEvent(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L440) +`fun handleBackgroundEvent(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L452) Handle the background event and send the appropriate pings. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/index.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/index.md index 493bb55b4ae..221cebe4bff 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/index.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/index.md @@ -2,7 +2,7 @@ # GleanInternalAPI -`open class GleanInternalAPI` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L42) +`open class GleanInternalAPI` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L44) ### Functions diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/initialize.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/initialize.md index 5c782b96859..ee55ba3778a 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/initialize.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/initialize.md @@ -2,7 +2,7 @@ # initialize -`fun initialize(applicationContext: , configuration: `[`Configuration`](../../mozilla.components.service.glean.config/-configuration/index.md)` = Configuration()): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L88) +`fun initialize(applicationContext: , configuration: `[`Configuration`](../../mozilla.components.service.glean.config/-configuration/index.md)` = Configuration()): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L90) Initialize Glean. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/is-initialized.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/is-initialized.md index 37ce3f588ec..8cd579f2882 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/is-initialized.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/is-initialized.md @@ -2,7 +2,7 @@ # isInitialized -`fun isInitialized(): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L148) +`fun isInitialized(): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L150) Returns true if the Glean library has been initialized. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/register-pings.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/register-pings.md index 717b388a66b..3f3a7b2171e 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/register-pings.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/register-pings.md @@ -2,7 +2,7 @@ # registerPings -`fun registerPings(pings: `[`Any`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L158) +`fun registerPings(pings: `[`Any`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L160) Register the pings generated from `pings.yaml` with Glean. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-active.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-active.md index a8dfe9dc6fe..4db1377d225 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-active.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-active.md @@ -2,7 +2,7 @@ # setExperimentActive -`fun setExperimentActive(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, branch: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, extra: `[`Map`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/index.html)`<`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`>? = null): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L255) +`fun setExperimentActive(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, branch: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, extra: `[`Map`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/index.html)`<`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`>? = null): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L267) Indicate that an experiment is running. Glean will then add an experiment annotation to the environment which is sent with pings. This diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-inactive.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-inactive.md index 9aabce7994b..aaf695b8f55 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-inactive.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-experiment-inactive.md @@ -2,7 +2,7 @@ # setExperimentInactive -`fun setExperimentInactive(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L268) +`fun setExperimentInactive(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L280) Indicate that an experiment is no longer running. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-upload-enabled.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-upload-enabled.md index af939724b60..0fed12c51ec 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-upload-enabled.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/set-upload-enabled.md @@ -2,7 +2,7 @@ # setUploadEnabled -`fun setUploadEnabled(enabled: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L180) +`fun setUploadEnabled(enabled: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L182) Enable or disable Glean collection and upload. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-get-experiment-data.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-get-experiment-data.md index c8e27c134f5..daf8ef3fad6 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-get-experiment-data.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-get-experiment-data.md @@ -2,7 +2,7 @@ # testGetExperimentData -`fun testGetExperimentData(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`RecordedExperimentData`](../../mozilla.components.service.glean.storages/-recorded-experiment-data/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L291) +`fun testGetExperimentData(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`RecordedExperimentData`](../../mozilla.components.service.glean.storages/-recorded-experiment-data/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L303) Returns the stored data for the requested active experiment, for testing purposes only. diff --git a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-is-experiment-active.md b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-is-experiment-active.md index 5b9bea156ea..45b48cb0d11 100644 --- a/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-is-experiment-active.md +++ b/docs/api/mozilla.components.service.glean/-glean-internal-a-p-i/test-is-experiment-active.md @@ -2,7 +2,7 @@ # testIsExperimentActive -`fun testIsExperimentActive(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L279) +`fun testIsExperimentActive(experimentId: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L291) Tests whether an experiment is active, for testing purposes only. diff --git a/docs/api/mozilla.components.service.glean/-glean.md b/docs/api/mozilla.components.service.glean/-glean.md index a3b23cd816b..6effe1ccd77 100644 --- a/docs/api/mozilla.components.service.glean/-glean.md +++ b/docs/api/mozilla.components.service.glean/-glean.md @@ -2,7 +2,7 @@ # Glean -`object Glean : `[`GleanInternalAPI`](-glean-internal-a-p-i/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L576) +`object Glean : `[`GleanInternalAPI`](-glean-internal-a-p-i/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt#L588) ### Inherited Functions diff --git a/docs/api/mozilla.components.support.test.rules/-webserver-rule/-init-.md b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/-init-.md similarity index 66% rename from docs/api/mozilla.components.support.test.rules/-webserver-rule/-init-.md rename to docs/api/mozilla.components.support.android.test.rules/-webserver-rule/-init-.md index 1da34244966..3daf4366386 100644 --- a/docs/api/mozilla.components.support.test.rules/-webserver-rule/-init-.md +++ b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/-init-.md @@ -1,4 +1,4 @@ -[android-components](../../index.md) / [mozilla.components.support.test.rules](../index.md) / [WebserverRule](index.md) / [<init>](./-init-.md) +[android-components](../../index.md) / [mozilla.components.support.android.test.rules](../index.md) / [WebserverRule](index.md) / [<init>](./-init-.md) # <init> diff --git a/docs/api/mozilla.components.support.test.rules/-webserver-rule/finished.md b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/finished.md similarity index 54% rename from docs/api/mozilla.components.support.test.rules/-webserver-rule/finished.md rename to docs/api/mozilla.components.support.android.test.rules/-webserver-rule/finished.md index 15ee850625b..46901c8b015 100644 --- a/docs/api/mozilla.components.support.test.rules/-webserver-rule/finished.md +++ b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/finished.md @@ -1,5 +1,5 @@ -[android-components](../../index.md) / [mozilla.components.support.test.rules](../index.md) / [WebserverRule](index.md) / [finished](./finished.md) +[android-components](../../index.md) / [mozilla.components.support.android.test.rules](../index.md) / [WebserverRule](index.md) / [finished](./finished.md) # finished -`protected fun finished(description: Description?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/test/src/main/java/mozilla/components/support/test/rules/WebserverRule.kt#L34) \ No newline at end of file +`protected fun finished(description: Description?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/android-test/src/main/java/mozilla/components/support/android/test/rules/WebserverRule.kt#L34) \ No newline at end of file diff --git a/docs/api/mozilla.components.support.test.rules/-webserver-rule/index.md b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/index.md similarity index 86% rename from docs/api/mozilla.components.support.test.rules/-webserver-rule/index.md rename to docs/api/mozilla.components.support.android.test.rules/-webserver-rule/index.md index 88ed037739c..8420c1b7bcc 100644 --- a/docs/api/mozilla.components.support.test.rules/-webserver-rule/index.md +++ b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/index.md @@ -1,8 +1,8 @@ -[android-components](../../index.md) / [mozilla.components.support.test.rules](../index.md) / [WebserverRule](./index.md) +[android-components](../../index.md) / [mozilla.components.support.android.test.rules](../index.md) / [WebserverRule](./index.md) # WebserverRule -`class WebserverRule : TestWatcher` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/test/src/main/java/mozilla/components/support/test/rules/WebserverRule.kt#L21) +`class WebserverRule : TestWatcher` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/android-test/src/main/java/mozilla/components/support/android/test/rules/WebserverRule.kt#L21) A [TestWatcher](#) junit rule that will serve content from assets in the test package. diff --git a/docs/api/mozilla.components.support.test.rules/-webserver-rule/starting.md b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/starting.md similarity index 54% rename from docs/api/mozilla.components.support.test.rules/-webserver-rule/starting.md rename to docs/api/mozilla.components.support.android.test.rules/-webserver-rule/starting.md index 215fbc34965..d99df5494f1 100644 --- a/docs/api/mozilla.components.support.test.rules/-webserver-rule/starting.md +++ b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/starting.md @@ -1,5 +1,5 @@ -[android-components](../../index.md) / [mozilla.components.support.test.rules](../index.md) / [WebserverRule](index.md) / [starting](./starting.md) +[android-components](../../index.md) / [mozilla.components.support.android.test.rules](../index.md) / [WebserverRule](index.md) / [starting](./starting.md) # starting -`protected fun starting(description: Description?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/test/src/main/java/mozilla/components/support/test/rules/WebserverRule.kt#L30) \ No newline at end of file +`protected fun starting(description: Description?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/android-test/src/main/java/mozilla/components/support/android/test/rules/WebserverRule.kt#L30) \ No newline at end of file diff --git a/docs/api/mozilla.components.support.test.rules/-webserver-rule/url.md b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/url.md similarity index 61% rename from docs/api/mozilla.components.support.test.rules/-webserver-rule/url.md rename to docs/api/mozilla.components.support.android.test.rules/-webserver-rule/url.md index 0ec549d8722..ce39fc6f442 100644 --- a/docs/api/mozilla.components.support.test.rules/-webserver-rule/url.md +++ b/docs/api/mozilla.components.support.android.test.rules/-webserver-rule/url.md @@ -1,5 +1,5 @@ -[android-components](../../index.md) / [mozilla.components.support.test.rules](../index.md) / [WebserverRule](index.md) / [url](./url.md) +[android-components](../../index.md) / [mozilla.components.support.android.test.rules](../index.md) / [WebserverRule](index.md) / [url](./url.md) # url -`fun url(path: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)` = ""): `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/test/src/main/java/mozilla/components/support/test/rules/WebserverRule.kt#L26) \ No newline at end of file +`fun url(path: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)` = ""): `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/support/android-test/src/main/java/mozilla/components/support/android/test/rules/WebserverRule.kt#L26) \ No newline at end of file diff --git a/docs/api/mozilla.components.support.test.rules/index.md b/docs/api/mozilla.components.support.android.test.rules/index.md similarity index 75% rename from docs/api/mozilla.components.support.test.rules/index.md rename to docs/api/mozilla.components.support.android.test.rules/index.md index b38baee37c7..818a70ca5e1 100644 --- a/docs/api/mozilla.components.support.test.rules/index.md +++ b/docs/api/mozilla.components.support.android.test.rules/index.md @@ -1,6 +1,6 @@ -[android-components](../index.md) / [mozilla.components.support.test.rules](./index.md) +[android-components](../index.md) / [mozilla.components.support.android.test.rules](./index.md) -## Package mozilla.components.support.test.rules +## Package mozilla.components.support.android.test.rules ### Types diff --git a/docs/api/package-list b/docs/api/package-list index 350dc23953b..516531d8b5d 100644 --- a/docs/api/package-list +++ b/docs/api/package-list @@ -107,6 +107,7 @@ mozilla.components.browser.tabstray mozilla.components.browser.tabstray.thumbnail mozilla.components.browser.toolbar mozilla.components.browser.toolbar.behavior +mozilla.components.browser.toolbar.display mozilla.components.concept.awesomebar mozilla.components.concept.engine mozilla.components.concept.engine.content.blocking @@ -211,6 +212,7 @@ mozilla.components.support.android.test mozilla.components.support.android.test.espresso mozilla.components.support.android.test.espresso.matcher mozilla.components.support.android.test.leaks +mozilla.components.support.android.test.rules mozilla.components.support.base.android mozilla.components.support.base.android.view mozilla.components.support.base.facts @@ -239,7 +241,6 @@ mozilla.components.support.test mozilla.components.support.test.ext mozilla.components.support.test.robolectric mozilla.components.support.test.robolectric.shadow -mozilla.components.support.test.rules mozilla.components.support.utils mozilla.components.tooling.fetch.tests mozilla.components.tooling.lint From 76d178ed789d461c9dd6ae4fe87851974b6194ca Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Thu, 8 Aug 2019 18:58:36 -0700 Subject: [PATCH 06/38] No issue: bump a-s to 0.37.0 Some nice improvements: - 0.37.0 fixes behaviour of `FirefoxAccount.disconnect` - device records will now be removed on logout. - 'wantsKeys' is no longer necessary, so we get a simpler API - new device type for upcoming integrations --- buildSrc/src/main/java/Dependencies.kt | 2 +- .../mozilla/components/concept/sync/Devices.kt | 3 +++ .../components/concept/sync/OAuthAccount.kt | 2 +- .../accounts/FirefoxAccountsAuthFeatureTest.kt | 4 ++-- .../components/service/fxa/FirefoxAccount.kt | 5 ++--- .../mozilla/components/service/fxa/Types.kt | 6 ++++++ .../service/fxa/manager/FxaAccountManager.kt | 2 +- .../service/fxa/FxaAccountManagerTest.kt | 18 +++++++++--------- docs/changelog.md | 5 +++++ .../org/mozilla/samples/fxa/MainActivity.kt | 6 ++---- .../src/main/res/values/strings.xml | 2 +- .../samples/sync/DeviceRecyclerViewAdapter.kt | 3 +++ 12 files changed, 36 insertions(+), 22 deletions(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 27c88c06a3b..beff526a693 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -26,7 +26,7 @@ object Versions { const val disklrucache = "2.0.2" const val leakcanary = "1.6.3" - const val mozilla_appservices = "0.36.0" + const val mozilla_appservices = "0.37.0" const val servo = "0.0.1.20181017.aa95911" const val material = "1.0.0" diff --git a/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt b/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt index 562f36f96ec..e31a1828a65 100644 --- a/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt +++ b/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt @@ -127,6 +127,9 @@ interface DeviceConstellationObserver { enum class DeviceType { DESKTOP, MOBILE, + TABLET, + TV, + VR, UNKNOWN } diff --git a/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt b/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt index 888ef436182..f41c445abb4 100644 --- a/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt +++ b/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt @@ -25,7 +25,7 @@ class AuthException(type: AuthExceptionType, cause: Exception? = null) : Throwab */ @SuppressWarnings("TooManyFunctions") interface OAuthAccount : AutoCloseable { - fun beginOAuthFlowAsync(scopes: Set, wantsKeys: Boolean): Deferred + fun beginOAuthFlowAsync(scopes: Set): Deferred fun beginPairingFlowAsync(pairingUrl: String, scopes: Set): Deferred fun getProfileAsync(ignoreCache: Boolean): Deferred fun getProfileAsync(): Deferred diff --git a/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt b/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt index 043350a9a12..36373eb06ee 100644 --- a/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt +++ b/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt @@ -129,7 +129,7 @@ class FirefoxAccountsAuthFeatureTest { val profile = Profile(uid = "testUID", avatar = null, email = "test@example.com", displayName = "test profile") `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) @@ -154,7 +154,7 @@ class FirefoxAccountsAuthFeatureTest { `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred(value = null)) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) diff --git a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt index bcd3a438225..1bafa03e12a 100644 --- a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt +++ b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt @@ -103,13 +103,12 @@ class FirefoxAccount internal constructor( * Constructs a URL used to begin the OAuth flow for the requested scopes and keys. * * @param scopes List of OAuth scopes for which the client wants access - * @param wantsKeys Fetch keys for end-to-end encryption of data from Mozilla-hosted services * @return Deferred that resolves to the flow URL when complete */ - override fun beginOAuthFlowAsync(scopes: Set, wantsKeys: Boolean): Deferred { + override fun beginOAuthFlowAsync(scopes: Set): Deferred { return scope.async { handleFxaExceptions(logger, "begin oauth flow", { null }) { - inner.beginOAuthFlow(scopes.toTypedArray(), wantsKeys) + inner.beginOAuthFlow(scopes.toTypedArray()) } } } diff --git a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt index b438428598c..1ba654fda7e 100644 --- a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt +++ b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt @@ -73,6 +73,9 @@ fun Device.Type.into(): mozilla.components.concept.sync.DeviceType { return when (this) { Device.Type.DESKTOP -> DeviceType.DESKTOP Device.Type.MOBILE -> DeviceType.MOBILE + Device.Type.TABLET -> DeviceType.TABLET + Device.Type.TV -> DeviceType.TV + Device.Type.VR -> DeviceType.VR Device.Type.UNKNOWN -> DeviceType.UNKNOWN } } @@ -81,6 +84,9 @@ fun mozilla.components.concept.sync.DeviceType.into(): Device.Type { return when (this) { DeviceType.DESKTOP -> Device.Type.DESKTOP DeviceType.MOBILE -> Device.Type.MOBILE + DeviceType.TABLET -> Device.Type.TABLET + DeviceType.TV -> Device.Type.TV + DeviceType.VR -> Device.Type.VR DeviceType.UNKNOWN -> Device.Type.UNKNOWN } } diff --git a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt index 8d2fc1b88e9..38fb6550712 100644 --- a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt +++ b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt @@ -744,7 +744,7 @@ open class FxaAccountManager( } private suspend fun doAuthenticate(): Event? { - val url = account.beginOAuthFlowAsync(scopes, true).await() + val url = account.beginOAuthFlowAsync(scopes).await() if (url == null) { oauthObservers.notifyObservers { onError() } return Event.FailedToAuthenticate diff --git a/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt b/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt index 60159a888f3..13ab5807876 100644 --- a/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt +++ b/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt @@ -721,7 +721,7 @@ class FxaAccountManagerTest { var accessTokenErrorCalled = false var latestMigrateAuthInfo: ShareableAuthInfo? = null - override fun beginOAuthFlowAsync(scopes: Set, wantsKeys: Boolean): Deferred { + override fun beginOAuthFlowAsync(scopes: Set): Deferred { return CompletableDeferred("auth://url") } @@ -1059,7 +1059,7 @@ class FxaAccountManagerTest { assertNull(manager.accountProfile()) // Try again, without any network problems this time. - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(constellation.initDeviceAsync(any(), any(), any())).thenReturn(CompletableDeferred(true)) assertEquals("auth://url", manager.beginAuthenticationAsync().await()) @@ -1230,7 +1230,7 @@ class FxaAccountManagerTest { `when`(mockAccount.deviceConstellation()).thenReturn(constellation) `when`(constellation.initDeviceAsync(any(), any(), any())).thenReturn(CompletableDeferred(true)) `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(value = null)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1302,7 +1302,7 @@ class FxaAccountManagerTest { // Our recovery flow should attempt to hit this API. Model the "can't recover" condition by returning false. `when`(mockAccount.checkAuthorizationStatusAsync(eq("profile"))).thenReturn(CompletableDeferred(false)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1358,7 +1358,7 @@ class FxaAccountManagerTest { // Our recovery flow should attempt to hit this API. Model the "don't know what's up" condition by returning null. `when`(mockAccount.checkAuthorizationStatusAsync(eq("profile"))).thenReturn(CompletableDeferred(value = null)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1424,7 +1424,7 @@ class FxaAccountManagerTest { // Recovery flow will hit this API, return a success. `when`(mockAccount.checkAuthorizationStatusAsync(eq("profile"))).thenReturn(CompletableDeferred(true)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1482,7 +1482,7 @@ class FxaAccountManagerTest { `when`(mockAccount.deviceConstellation()).thenReturn(constellation) `when`(constellation.initDeviceAsync(any(), any(), any())).thenReturn(CompletableDeferred(true)) `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(exceptionalProfile) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1523,7 +1523,7 @@ class FxaAccountManagerTest { ): FxaAccountManager { `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. @@ -1555,7 +1555,7 @@ class FxaAccountManagerTest { ): FxaAccountManager { `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred(value = null)) + `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. diff --git a/docs/changelog.md b/docs/changelog.md index 87a2d926395..6ecf6211e86 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -35,6 +35,11 @@ permalink: /changelog/ ) ``` +* **concept-sync**, **service-firefox-account** + * ⚠️ **This is a breaking change** + * In `OAuthAccount` (and by extension, `FirefoxAccount`) `beginOAuthFlowAsync` no longer need to specify `wantsKeys` parameter; it's automatically inferred from the requested `scopes`. + * Three new device types now available: `tablet`, `tv`, `vr`. + # 7.0.0 * [Commits](https://github.com/mozilla-mobile/android-components/compare/v6.0.2...v7.0.0) diff --git a/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt b/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt index 4112d5ff823..db177698750 100644 --- a/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt +++ b/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt @@ -36,7 +36,6 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList private var scopesWithoutKeys: Set = setOf("profile") private var scopesWithKeys: Set = setOf("profile", "https://identity.mozilla.com/apps/oldsync") private var scopes: Set = scopesWithoutKeys - private var wantsKeys: Boolean = false private lateinit var qrFeature: QrFeature @@ -90,7 +89,7 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList findViewById(R.id.buttonCustomTabs).setOnClickListener { launch { - account.beginOAuthFlowAsync(scopes, wantsKeys).await()?.let { + account.beginOAuthFlowAsync(scopes).await()?.let { openTab(it) } } @@ -98,7 +97,7 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList findViewById(R.id.buttonWebView).setOnClickListener { launch { - account.beginOAuthFlowAsync(scopes, wantsKeys).await()?.let { + account.beginOAuthFlowAsync(scopes).await()?.let { openWebView(it) } } @@ -115,7 +114,6 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList } findViewById(R.id.checkboxKeys).setOnCheckedChangeListener { _, isChecked -> - wantsKeys = isChecked scopes = if (isChecked) scopesWithKeys else scopesWithoutKeys } } diff --git a/samples/firefox-accounts/src/main/res/values/strings.xml b/samples/firefox-accounts/src/main/res/values/strings.xml index 1907df916c9..9e0ab72d6dd 100644 --- a/samples/firefox-accounts/src/main/res/values/strings.xml +++ b/samples/firefox-accounts/src/main/res/values/strings.xml @@ -10,5 +10,5 @@ Signed in: %1$s FxA Log Out Logged out! - Get keys? + Request sync scope? diff --git a/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt b/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt index f4e05b522b4..6f00608e4a7 100644 --- a/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt +++ b/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt @@ -43,6 +43,9 @@ class DeviceRecyclerViewAdapter( holder.typeView.text = when (item.deviceType) { DeviceType.DESKTOP -> "Desktop" DeviceType.MOBILE -> "Mobile" + DeviceType.TABLET -> "Tablet" + DeviceType.TV -> "TV" + DeviceType.VR -> "VR" DeviceType.UNKNOWN -> "Unknown" } From 55a84ffeeadf85272e1b7b69e7ec1e9d364741b8 Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Fri, 9 Aug 2019 11:14:18 -0700 Subject: [PATCH 07/38] Revert "No issue: bump a-s to 0.37.0" This reverts commit 76d178ed789d461c9dd6ae4fe87851974b6194ca. --- buildSrc/src/main/java/Dependencies.kt | 2 +- .../mozilla/components/concept/sync/Devices.kt | 3 --- .../components/concept/sync/OAuthAccount.kt | 2 +- .../accounts/FirefoxAccountsAuthFeatureTest.kt | 4 ++-- .../components/service/fxa/FirefoxAccount.kt | 5 +++-- .../mozilla/components/service/fxa/Types.kt | 6 ------ .../service/fxa/manager/FxaAccountManager.kt | 2 +- .../service/fxa/FxaAccountManagerTest.kt | 18 +++++++++--------- docs/changelog.md | 5 ----- .../org/mozilla/samples/fxa/MainActivity.kt | 6 ++++-- .../src/main/res/values/strings.xml | 2 +- .../samples/sync/DeviceRecyclerViewAdapter.kt | 3 --- 12 files changed, 22 insertions(+), 36 deletions(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index beff526a693..27c88c06a3b 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -26,7 +26,7 @@ object Versions { const val disklrucache = "2.0.2" const val leakcanary = "1.6.3" - const val mozilla_appservices = "0.37.0" + const val mozilla_appservices = "0.36.0" const val servo = "0.0.1.20181017.aa95911" const val material = "1.0.0" diff --git a/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt b/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt index e31a1828a65..562f36f96ec 100644 --- a/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt +++ b/components/concept/sync/src/main/java/mozilla/components/concept/sync/Devices.kt @@ -127,9 +127,6 @@ interface DeviceConstellationObserver { enum class DeviceType { DESKTOP, MOBILE, - TABLET, - TV, - VR, UNKNOWN } diff --git a/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt b/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt index f41c445abb4..888ef436182 100644 --- a/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt +++ b/components/concept/sync/src/main/java/mozilla/components/concept/sync/OAuthAccount.kt @@ -25,7 +25,7 @@ class AuthException(type: AuthExceptionType, cause: Exception? = null) : Throwab */ @SuppressWarnings("TooManyFunctions") interface OAuthAccount : AutoCloseable { - fun beginOAuthFlowAsync(scopes: Set): Deferred + fun beginOAuthFlowAsync(scopes: Set, wantsKeys: Boolean): Deferred fun beginPairingFlowAsync(pairingUrl: String, scopes: Set): Deferred fun getProfileAsync(ignoreCache: Boolean): Deferred fun getProfileAsync(): Deferred diff --git a/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt b/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt index 36373eb06ee..043350a9a12 100644 --- a/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt +++ b/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt @@ -129,7 +129,7 @@ class FirefoxAccountsAuthFeatureTest { val profile = Profile(uid = "testUID", avatar = null, email = "test@example.com", displayName = "test profile") `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) @@ -154,7 +154,7 @@ class FirefoxAccountsAuthFeatureTest { `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred(value = null)) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) diff --git a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt index 1bafa03e12a..bcd3a438225 100644 --- a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt +++ b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/FirefoxAccount.kt @@ -103,12 +103,13 @@ class FirefoxAccount internal constructor( * Constructs a URL used to begin the OAuth flow for the requested scopes and keys. * * @param scopes List of OAuth scopes for which the client wants access + * @param wantsKeys Fetch keys for end-to-end encryption of data from Mozilla-hosted services * @return Deferred that resolves to the flow URL when complete */ - override fun beginOAuthFlowAsync(scopes: Set): Deferred { + override fun beginOAuthFlowAsync(scopes: Set, wantsKeys: Boolean): Deferred { return scope.async { handleFxaExceptions(logger, "begin oauth flow", { null }) { - inner.beginOAuthFlow(scopes.toTypedArray()) + inner.beginOAuthFlow(scopes.toTypedArray(), wantsKeys) } } } diff --git a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt index 1ba654fda7e..b438428598c 100644 --- a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt +++ b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/Types.kt @@ -73,9 +73,6 @@ fun Device.Type.into(): mozilla.components.concept.sync.DeviceType { return when (this) { Device.Type.DESKTOP -> DeviceType.DESKTOP Device.Type.MOBILE -> DeviceType.MOBILE - Device.Type.TABLET -> DeviceType.TABLET - Device.Type.TV -> DeviceType.TV - Device.Type.VR -> DeviceType.VR Device.Type.UNKNOWN -> DeviceType.UNKNOWN } } @@ -84,9 +81,6 @@ fun mozilla.components.concept.sync.DeviceType.into(): Device.Type { return when (this) { DeviceType.DESKTOP -> Device.Type.DESKTOP DeviceType.MOBILE -> Device.Type.MOBILE - DeviceType.TABLET -> Device.Type.TABLET - DeviceType.TV -> Device.Type.TV - DeviceType.VR -> Device.Type.VR DeviceType.UNKNOWN -> Device.Type.UNKNOWN } } diff --git a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt index 38fb6550712..8d2fc1b88e9 100644 --- a/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt +++ b/components/service/firefox-accounts/src/main/java/mozilla/components/service/fxa/manager/FxaAccountManager.kt @@ -744,7 +744,7 @@ open class FxaAccountManager( } private suspend fun doAuthenticate(): Event? { - val url = account.beginOAuthFlowAsync(scopes).await() + val url = account.beginOAuthFlowAsync(scopes, true).await() if (url == null) { oauthObservers.notifyObservers { onError() } return Event.FailedToAuthenticate diff --git a/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt b/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt index 13ab5807876..60159a888f3 100644 --- a/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt +++ b/components/service/firefox-accounts/src/test/java/mozilla/components/service/fxa/FxaAccountManagerTest.kt @@ -721,7 +721,7 @@ class FxaAccountManagerTest { var accessTokenErrorCalled = false var latestMigrateAuthInfo: ShareableAuthInfo? = null - override fun beginOAuthFlowAsync(scopes: Set): Deferred { + override fun beginOAuthFlowAsync(scopes: Set, wantsKeys: Boolean): Deferred { return CompletableDeferred("auth://url") } @@ -1059,7 +1059,7 @@ class FxaAccountManagerTest { assertNull(manager.accountProfile()) // Try again, without any network problems this time. - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(constellation.initDeviceAsync(any(), any(), any())).thenReturn(CompletableDeferred(true)) assertEquals("auth://url", manager.beginAuthenticationAsync().await()) @@ -1230,7 +1230,7 @@ class FxaAccountManagerTest { `when`(mockAccount.deviceConstellation()).thenReturn(constellation) `when`(constellation.initDeviceAsync(any(), any(), any())).thenReturn(CompletableDeferred(true)) `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(value = null)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1302,7 +1302,7 @@ class FxaAccountManagerTest { // Our recovery flow should attempt to hit this API. Model the "can't recover" condition by returning false. `when`(mockAccount.checkAuthorizationStatusAsync(eq("profile"))).thenReturn(CompletableDeferred(false)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1358,7 +1358,7 @@ class FxaAccountManagerTest { // Our recovery flow should attempt to hit this API. Model the "don't know what's up" condition by returning null. `when`(mockAccount.checkAuthorizationStatusAsync(eq("profile"))).thenReturn(CompletableDeferred(value = null)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1424,7 +1424,7 @@ class FxaAccountManagerTest { // Recovery flow will hit this API, return a success. `when`(mockAccount.checkAuthorizationStatusAsync(eq("profile"))).thenReturn(CompletableDeferred(true)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1482,7 +1482,7 @@ class FxaAccountManagerTest { `when`(mockAccount.deviceConstellation()).thenReturn(constellation) `when`(constellation.initDeviceAsync(any(), any(), any())).thenReturn(CompletableDeferred(true)) `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(exceptionalProfile) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. `when`(accountStorage.read()).thenReturn(null) @@ -1523,7 +1523,7 @@ class FxaAccountManagerTest { ): FxaAccountManager { `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred("auth://url")) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred("auth://url")) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. @@ -1555,7 +1555,7 @@ class FxaAccountManagerTest { ): FxaAccountManager { `when`(mockAccount.getProfileAsync(anyBoolean())).thenReturn(CompletableDeferred(profile)) - `when`(mockAccount.beginOAuthFlowAsync(any())).thenReturn(CompletableDeferred(value = null)) + `when`(mockAccount.beginOAuthFlowAsync(any(), anyBoolean())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.beginPairingFlowAsync(anyString(), any())).thenReturn(CompletableDeferred(value = null)) `when`(mockAccount.completeOAuthFlowAsync(anyString(), anyString())).thenReturn(CompletableDeferred(true)) // There's no account at the start. diff --git a/docs/changelog.md b/docs/changelog.md index 6ecf6211e86..87a2d926395 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -35,11 +35,6 @@ permalink: /changelog/ ) ``` -* **concept-sync**, **service-firefox-account** - * ⚠️ **This is a breaking change** - * In `OAuthAccount` (and by extension, `FirefoxAccount`) `beginOAuthFlowAsync` no longer need to specify `wantsKeys` parameter; it's automatically inferred from the requested `scopes`. - * Three new device types now available: `tablet`, `tv`, `vr`. - # 7.0.0 * [Commits](https://github.com/mozilla-mobile/android-components/compare/v6.0.2...v7.0.0) diff --git a/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt b/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt index db177698750..4112d5ff823 100644 --- a/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt +++ b/samples/firefox-accounts/src/main/java/org/mozilla/samples/fxa/MainActivity.kt @@ -36,6 +36,7 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList private var scopesWithoutKeys: Set = setOf("profile") private var scopesWithKeys: Set = setOf("profile", "https://identity.mozilla.com/apps/oldsync") private var scopes: Set = scopesWithoutKeys + private var wantsKeys: Boolean = false private lateinit var qrFeature: QrFeature @@ -89,7 +90,7 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList findViewById(R.id.buttonCustomTabs).setOnClickListener { launch { - account.beginOAuthFlowAsync(scopes).await()?.let { + account.beginOAuthFlowAsync(scopes, wantsKeys).await()?.let { openTab(it) } } @@ -97,7 +98,7 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList findViewById(R.id.buttonWebView).setOnClickListener { launch { - account.beginOAuthFlowAsync(scopes).await()?.let { + account.beginOAuthFlowAsync(scopes, wantsKeys).await()?.let { openWebView(it) } } @@ -114,6 +115,7 @@ open class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteList } findViewById(R.id.checkboxKeys).setOnCheckedChangeListener { _, isChecked -> + wantsKeys = isChecked scopes = if (isChecked) scopesWithKeys else scopesWithoutKeys } } diff --git a/samples/firefox-accounts/src/main/res/values/strings.xml b/samples/firefox-accounts/src/main/res/values/strings.xml index 9e0ab72d6dd..1907df916c9 100644 --- a/samples/firefox-accounts/src/main/res/values/strings.xml +++ b/samples/firefox-accounts/src/main/res/values/strings.xml @@ -10,5 +10,5 @@ Signed in: %1$s FxA Log Out Logged out! - Request sync scope? + Get keys? diff --git a/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt b/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt index 6f00608e4a7..f4e05b522b4 100644 --- a/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt +++ b/samples/sync/src/main/java/org/mozilla/samples/sync/DeviceRecyclerViewAdapter.kt @@ -43,9 +43,6 @@ class DeviceRecyclerViewAdapter( holder.typeView.text = when (item.deviceType) { DeviceType.DESKTOP -> "Desktop" DeviceType.MOBILE -> "Mobile" - DeviceType.TABLET -> "Tablet" - DeviceType.TV -> "TV" - DeviceType.VR -> "VR" DeviceType.UNKNOWN -> "Unknown" } From cec85e112bf968eccd6fa7ea594c82350b2c4bb5 Mon Sep 17 00:00:00 2001 From: Travis Long Date: Fri, 9 Aug 2019 14:57:27 -0500 Subject: [PATCH 08/38] Bug 1572796 - Improve service-experiments public API docstrings --- .../service/experiments/Configuration.kt | 3 ++ .../service/experiments/Experiments.kt | 45 ++++++++++++++++--- .../debug/ExperimentsDebugActivity.kt | 38 ++++++++++++++-- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/components/service/experiments/src/main/java/mozilla/components/service/experiments/Configuration.kt b/components/service/experiments/src/main/java/mozilla/components/service/experiments/Configuration.kt index ad1b049dc5a..8e894f32237 100644 --- a/components/service/experiments/src/main/java/mozilla/components/service/experiments/Configuration.kt +++ b/components/service/experiments/src/main/java/mozilla/components/service/experiments/Configuration.kt @@ -11,6 +11,9 @@ import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient * The Configuration class describes how to configure Experiments. * * @property httpClient The HTTP client implementation to use for uploading pings. + * @property kintoEndpoint the endpoint to fetch experiments from, must be one of: + * [ExperimentsUpdater.KINTO_ENDPOINT_DEV], [ExperimentsUpdater.KINTO_ENDPOINT_STAGING], or + * [ExperimentsUpdater.KINTO_ENDPOINT_PROD] */ data class Configuration( val httpClient: Lazy = lazy { HttpURLConnectionClient() }, diff --git a/components/service/experiments/src/main/java/mozilla/components/service/experiments/Experiments.kt b/components/service/experiments/src/main/java/mozilla/components/service/experiments/Experiments.kt index ca65b6a18b6..68e9fbe3f4a 100644 --- a/components/service/experiments/src/main/java/mozilla/components/service/experiments/Experiments.kt +++ b/components/service/experiments/src/main/java/mozilla/components/service/experiments/Experiments.kt @@ -12,7 +12,7 @@ import androidx.annotation.VisibleForTesting import java.io.File /** - * Entry point of the library. + * This is the main experiments API, which is exposed through the global [Experiments] object. */ @Suppress("TooManyFunctions") open class ExperimentsInternalAPI internal constructor() { @@ -51,6 +51,8 @@ open class ExperimentsInternalAPI internal constructor() { * as shared preferences. As we cannot enforce through the compiler that the context pass to * the initialize function is a applicationContext, there could potentially be a memory leak * if the initializing application doesn't comply. + * + * @param configuration [Configuration] containing information about the experiments endpoint. */ fun initialize( applicationContext: Context, @@ -91,11 +93,17 @@ open class ExperimentsInternalAPI internal constructor() { updater.initialize(configuration) } + /** + * Returns the [ExperimentsUpdater] for the given [Context]. + */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun getExperimentsUpdater(context: Context): ExperimentsUpdater { return ExperimentsUpdater(context, this) } + /** + * Returns the [FlatFileExperimentStorage] for the given [Context] + */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun getExperimentsStorage(context: Context): FlatFileExperimentStorage { return FlatFileExperimentStorage( @@ -122,8 +130,11 @@ open class ExperimentsInternalAPI internal constructor() { } /** - * Requests new experiments from the server and - * saves them to local storage + * Handles the required tasks when new experiments have been fetched from the server. + * + * This includes: + * - Storing the experiments that have been freshly retrieved from the server. + * - Updating the active experiment */ @Synchronized internal fun onExperimentsUpdated(serverState: ExperimentsSnapshot) { @@ -132,7 +143,6 @@ open class ExperimentsInternalAPI internal constructor() { experimentsResult = serverState storage.save(serverState) - // TODO // Choices here: // 1) There currently is an active experiment. // 1a) Should it stop? E.g. because it was deleted. If so, continue with 2. @@ -161,6 +171,10 @@ open class ExperimentsInternalAPI internal constructor() { } } + /** + * Evaluates the current [experimentsResult] to determine enrollment in any experiments, + * including reporting enrollment in an experiment in Glean. + */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun findAndStartActiveExperiment() { assert(activeExperiment == null) { "Should not have an active experiment" } @@ -173,6 +187,10 @@ open class ExperimentsInternalAPI internal constructor() { } } + /** + * Performs the necessary tasks to stop the active experiment, including reporting this to + * telemetry via Glean. + */ private fun stopActiveExperiment() { assert(activeExperiment != null) { "Should have an active experiment" } @@ -184,6 +202,9 @@ open class ExperimentsInternalAPI internal constructor() { activeExperiment = null } + /** + * This function finds and returns any active experiments from persisted storage. + */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun loadActiveExperiment( context: Context, @@ -244,6 +265,10 @@ open class ExperimentsInternalAPI internal constructor() { return evaluator.getExperiment(ExperimentDescriptor(experimentId), experimentsResult.experiments) } + /** + * Helper function to perform the tasks necessary to override the experiment once it has been + * set using [setOverride] or [setOverrideNow]. + */ private fun overrideActiveExperiment() { evaluator.findActiveExperiment(context, experimentsResult.experiments)?.let { logger.info("""Setting override experiment - id="${it.experiment.id}", branch="${it.branch}"""") @@ -355,11 +380,21 @@ open class ExperimentsInternalAPI internal constructor() { companion object { private const val LOG_TAG = "experiments" private const val EXPERIMENTS_DATA_DIR = "experiments-service" - private const val EXPERIMENTS_JSON_FILENAME = "experiments.json" } } +/** + * The main Experiments object. + * + * This is a global object that must be initialized by the application by calling the [initialize] + * function before the experiments library can fetch updates from the server or be used to determine + * experiment enrollment. + * + * ``` + * Experiments.initialize(applicationContext) + * ``` + */ @SuppressLint("StaticFieldLeak") object Experiments : ExperimentsInternalAPI() { internal const val SCHEMA_VERSION = 1 diff --git a/components/service/experiments/src/main/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivity.kt b/components/service/experiments/src/main/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivity.kt index 79b773b9207..870dc2f5059 100644 --- a/components/service/experiments/src/main/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivity.kt +++ b/components/service/experiments/src/main/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivity.kt @@ -16,6 +16,20 @@ import mozilla.components.service.experiments.Experiments import mozilla.components.service.experiments.ExperimentsUpdater import mozilla.components.support.base.log.logger.Logger +/** + * Debugging activity exported by service-experiments to allow easier debugging. This accepts + * commands that can force the library to do the following: + * - Fetch or update experiments + * - Change the Kinto endpoint to the `dev`, `staging`, or `prod` endpoint + * - Override the active experiment to a branch specified by the `branch` command + * - Clear any overridden experiment + * + * See here for more information on using the ExperimentsDebugActivity: + * https://github.com/mozilla-mobile/android-components/tree/master/components/service/experiments#experimentsdebugactivity-usage + * + * See the adb developer docs for more info: + * https://developer.android.com/studio/command-line/adb#am + */ class ExperimentsDebugActivity : Activity() { private val logger = Logger(LOG_TAG) @@ -28,16 +42,34 @@ class ExperimentsDebugActivity : Activity() { private const val LOG_TAG = "ExperimentsDebugActivity" // This is a list of the currently accepted commands + /** + * Fetch experiments from the server and update the active experiment if necessary. + */ const val UPDATE_EXPERIMENTS_EXTRA_KEY = "updateExperiments" + /** + * Sets the Kinto endpoint to the supplied endpoint. + * Must be one of: `dev`, `staging`, or `prod`. + */ const val SET_KINTO_INSTANCE_EXTRA_KEY = "setKintoInstance" - - // Both of these need to be supplied in order to select both the branch and the - // ExperimentDescriptor.id of the experiment to override. + /** + * Overrides the current experiment and set the active experiment to the given `branch`. + * This command requires two parameters to be passed, `overrideExperiment` and `branch` in + * order for it to work. + */ const val OVERRIDE_EXPERIMENT_EXTRA_KEY = "overrideExperiment" + /** + * Used only with [OVERRIDE_EXPERIMENT_EXTRA_KEY]. + */ const val OVERRIDE_BRANCH_EXTRA_KEY = "branch" + /** + * Clears any existing overrides. + */ const val OVERRIDE_CLEAR_ALL_EXTRA_KEY = "clearAllOverrides" } + /** + * On creation of the debug activity, process the command switches + */ @Suppress("ComplexMethod") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) From 103b6df66fa646aabad93adb73b20e65e9b1c324 Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Thu, 8 Aug 2019 14:13:36 +0000 Subject: [PATCH 09/38] Update GeckoView (nightly) (20190808-141335) --- buildSrc/src/main/java/Gecko.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Gecko.kt b/buildSrc/src/main/java/Gecko.kt index 94d05591e1d..87d286ad00e 100644 --- a/buildSrc/src/main/java/Gecko.kt +++ b/buildSrc/src/main/java/Gecko.kt @@ -6,7 +6,7 @@ internal object GeckoVersions { /** * GeckoView Nightly Version. */ - const val nightly_version = "70.0.20190807095705" + const val nightly_version = "70.0.20190808093310" /** * GeckoView Beta Version. From 8f87df870006c19b20102a675e0544cb21e6d91b Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Fri, 9 Aug 2019 18:46:48 +0000 Subject: [PATCH 10/38] Update Public Suffix List (20190809-184647) --- .../src/main/assets/publicsuffixes | Bin 103353 -> 103289 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/lib/publicsuffixlist/src/main/assets/publicsuffixes b/components/lib/publicsuffixlist/src/main/assets/publicsuffixes index ef889ddae442ff0cda460665cba8ebac1009806a..b1ec6eca7fb6aa25c15258c738c9ee1a975bee21 100644 GIT binary patch delta 45 zcmV+|0Mh@trv~|^1_S^BlKQa(^(V9aC!}PvtBj-(vsa!gV3U*nKC|Nfp-Q)lNdYcO D_Q)0k delta 94 zcmeyljBV#~HWmiP$yOU#zN$0kZ2qRcJcTW_vOF~>XY*bafr Date: Fri, 2 Aug 2019 11:23:13 +0200 Subject: [PATCH 11/38] Use PlaybackStateCompat everywhere. --- .../java/mozilla/components/feature/media/ext/MediaState.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt b/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt index 5084c49e7ab..923f886e74d 100644 --- a/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt +++ b/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt @@ -4,7 +4,6 @@ package mozilla.components.feature.media.ext -import android.media.session.PlaybackState import android.support.v4.media.session.PlaybackStateCompat import mozilla.components.concept.engine.media.Media import mozilla.components.feature.media.state.MediaState @@ -32,8 +31,8 @@ internal fun MediaState.toPlaybackState() = .setState( when (this) { is MediaState.Playing -> PlaybackStateCompat.STATE_PLAYING - is MediaState.Paused -> PlaybackState.STATE_PAUSED - is MediaState.None -> PlaybackState.STATE_NONE + is MediaState.Paused -> PlaybackStateCompat.STATE_PAUSED + is MediaState.None -> PlaybackStateCompat.STATE_NONE }, // Time state not exposed yet: // https://github.com/mozilla-mobile/android-components/issues/2458 From 12e1547ee6a6fc1e80d8d2e4e4ec8c9987b7183c Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Fri, 2 Aug 2019 15:41:41 +0200 Subject: [PATCH 12/38] Issue #2454: Expose "duration" of media. --- .../browser/engine/gecko/media/GeckoMedia.kt | 10 ++++-- .../engine/gecko/media/GeckoMediaTest.kt | 35 +++++++++++++++++++ .../browser/engine/gecko/media/GeckoMedia.kt | 10 ++++-- .../engine/gecko/media/GeckoMediaTest.kt | 35 +++++++++++++++++++ .../browser/engine/gecko/media/GeckoMedia.kt | 10 ++++-- .../engine/gecko/media/GeckoMediaTest.kt | 35 +++++++++++++++++++ .../components/concept/engine/media/Media.kt | 15 ++++++++ .../concept/engine/media/MediaTest.kt | 1 + 8 files changed, 145 insertions(+), 6 deletions(-) diff --git a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt index 68e77524d5d..2c9e77415d8 100644 --- a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt +++ b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt @@ -26,6 +26,9 @@ internal class GeckoMedia( ) : Media() { override val controller: Controller = GeckoMediaController(mediaElement) + override var metadata: Metadata = Metadata() + internal set + init { mediaElement.delegate = MediaDelegate(this) } @@ -44,7 +47,7 @@ internal class GeckoMedia( } private class MediaDelegate( - private val media: Media + private val media: GeckoMedia ) : MediaElement.Delegate { override fun onPlaybackStateChange(mediaElement: MediaElement, mediaState: Int) { @@ -63,8 +66,11 @@ private class MediaDelegate( } } + override fun onMetadataChange(mediaElement: MediaElement, metaData: MediaElement.Metadata) { + media.metadata = Media.Metadata(metaData.duration) + } + override fun onReadyStateChange(mediaElement: MediaElement, readyState: Int) = Unit - override fun onMetadataChange(mediaElement: MediaElement, metaData: MediaElement.Metadata) = Unit override fun onLoadProgress(mediaElement: MediaElement, progressInfo: MediaElement.LoadProgressInfo) = Unit override fun onVolumeChange(mediaElement: MediaElement, volume: Double, muted: Boolean) = Unit override fun onTimeChange(mediaElement: MediaElement, time: Double) = Unit diff --git a/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt b/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt index 58620bf5186..34d3111f9df 100644 --- a/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt +++ b/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt @@ -7,6 +7,7 @@ package mozilla.components.browser.engine.gecko.media import mozilla.components.concept.engine.media.Media import mozilla.components.support.test.argumentCaptor import mozilla.components.support.test.mock +import mozilla.components.test.ReflectionUtils import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test @@ -84,4 +85,38 @@ class GeckoMediaTest { delegate.onPlaybackStateChange(mediaElement, MediaElement.MEDIA_STATE_PLAYING) verify(observer).onPlaybackStateChanged(media, Media.PlaybackState.PLAYING) } + + @Test + fun `GeckoMedia exposes Metadata`() { + val mediaElement: MediaElement = mock() + + val media = GeckoMedia(mediaElement) + + val captor = argumentCaptor() + verify(mediaElement).delegate = captor.capture() + + assertEquals(-1.0, media.metadata.duration, 0.0001) + + val delegate = captor.value + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 5.0)) + assertEquals(5.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 572.0)) + assertEquals(572.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 0.0)) + assertEquals(0.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = -1.0)) + assertEquals(-1.0, media.metadata.duration, 0.0001) + } +} + +private class MockedGeckoMetadata( + duration: Double +) : MediaElement.Metadata() { + init { + ReflectionUtils.setField(this, "duration", duration) + } } diff --git a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt index 68e77524d5d..2c9e77415d8 100644 --- a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt +++ b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt @@ -26,6 +26,9 @@ internal class GeckoMedia( ) : Media() { override val controller: Controller = GeckoMediaController(mediaElement) + override var metadata: Metadata = Metadata() + internal set + init { mediaElement.delegate = MediaDelegate(this) } @@ -44,7 +47,7 @@ internal class GeckoMedia( } private class MediaDelegate( - private val media: Media + private val media: GeckoMedia ) : MediaElement.Delegate { override fun onPlaybackStateChange(mediaElement: MediaElement, mediaState: Int) { @@ -63,8 +66,11 @@ private class MediaDelegate( } } + override fun onMetadataChange(mediaElement: MediaElement, metaData: MediaElement.Metadata) { + media.metadata = Media.Metadata(metaData.duration) + } + override fun onReadyStateChange(mediaElement: MediaElement, readyState: Int) = Unit - override fun onMetadataChange(mediaElement: MediaElement, metaData: MediaElement.Metadata) = Unit override fun onLoadProgress(mediaElement: MediaElement, progressInfo: MediaElement.LoadProgressInfo) = Unit override fun onVolumeChange(mediaElement: MediaElement, volume: Double, muted: Boolean) = Unit override fun onTimeChange(mediaElement: MediaElement, time: Double) = Unit diff --git a/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt b/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt index 58620bf5186..34d3111f9df 100644 --- a/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt +++ b/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt @@ -7,6 +7,7 @@ package mozilla.components.browser.engine.gecko.media import mozilla.components.concept.engine.media.Media import mozilla.components.support.test.argumentCaptor import mozilla.components.support.test.mock +import mozilla.components.test.ReflectionUtils import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test @@ -84,4 +85,38 @@ class GeckoMediaTest { delegate.onPlaybackStateChange(mediaElement, MediaElement.MEDIA_STATE_PLAYING) verify(observer).onPlaybackStateChanged(media, Media.PlaybackState.PLAYING) } + + @Test + fun `GeckoMedia exposes Metadata`() { + val mediaElement: MediaElement = mock() + + val media = GeckoMedia(mediaElement) + + val captor = argumentCaptor() + verify(mediaElement).delegate = captor.capture() + + assertEquals(-1.0, media.metadata.duration, 0.0001) + + val delegate = captor.value + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 5.0)) + assertEquals(5.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 572.0)) + assertEquals(572.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 0.0)) + assertEquals(0.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = -1.0)) + assertEquals(-1.0, media.metadata.duration, 0.0001) + } +} + +private class MockedGeckoMetadata( + duration: Double +) : MediaElement.Metadata() { + init { + ReflectionUtils.setField(this, "duration", duration) + } } diff --git a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt index 7c815261847..c3347d1a733 100644 --- a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt +++ b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMedia.kt @@ -26,6 +26,9 @@ internal class GeckoMedia( ) : Media() { override val controller: Controller = GeckoMediaController(mediaElement) + override var metadata: Metadata = Metadata() + internal set + init { mediaElement.delegate = MediaDelegate(this) } @@ -44,7 +47,7 @@ internal class GeckoMedia( } private class MediaDelegate( - private val media: Media + private val media: GeckoMedia ) : MediaElement.Delegate { @Suppress("ComplexMethod") override fun onPlaybackStateChange(mediaElement: MediaElement, mediaState: Int) { @@ -63,8 +66,11 @@ private class MediaDelegate( } } + override fun onMetadataChange(mediaElement: MediaElement, metaData: MediaElement.Metadata) { + media.metadata = Media.Metadata(metaData.duration) + } + override fun onReadyStateChange(mediaElement: MediaElement, readyState: Int) = Unit - override fun onMetadataChange(mediaElement: MediaElement, metaData: MediaElement.Metadata) = Unit override fun onLoadProgress(mediaElement: MediaElement, progressInfo: MediaElement.LoadProgressInfo) = Unit override fun onVolumeChange(mediaElement: MediaElement, volume: Double, muted: Boolean) = Unit override fun onTimeChange(mediaElement: MediaElement, time: Double) = Unit diff --git a/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt b/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt index 8874e790268..e0daaf2fafb 100644 --- a/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt +++ b/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaTest.kt @@ -7,6 +7,7 @@ package mozilla.components.browser.engine.gecko.media import mozilla.components.concept.engine.media.Media import mozilla.components.support.test.argumentCaptor import mozilla.components.support.test.mock +import mozilla.components.test.ReflectionUtils import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test @@ -67,4 +68,38 @@ class GeckoMediaTest { assertTrue(media.controller is GeckoMediaController) } + + @Test + fun `GeckoMedia exposes Metadata`() { + val mediaElement: MediaElement = mock() + + val media = GeckoMedia(mediaElement) + + val captor = argumentCaptor() + verify(mediaElement).delegate = captor.capture() + + assertEquals(-1.0, media.metadata.duration, 0.0001) + + val delegate = captor.value + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 5.0)) + assertEquals(5.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 572.0)) + assertEquals(572.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = 0.0)) + assertEquals(0.0, media.metadata.duration, 0.0001) + + delegate.onMetadataChange(mediaElement, MockedGeckoMetadata(duration = -1.0)) + assertEquals(-1.0, media.metadata.duration, 0.0001) + } +} + +private class MockedGeckoMetadata( + duration: Double +) : MediaElement.Metadata() { + init { + ReflectionUtils.setField(this, "duration", duration) + } } diff --git a/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt b/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt index a3bc7aae747..f55f66d5d94 100644 --- a/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt +++ b/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt @@ -26,11 +26,17 @@ abstract class Media( */ abstract val controller: Controller + /** + * The [Metadata] + */ + abstract val metadata: Metadata + /** * Interface to be implemented by classes that want to observe a media element. */ interface Observer { fun onPlaybackStateChanged(media: Media, playbackState: PlaybackState) = Unit + fun onMetadataChanged(media: Media, metadata: Metadata) = Unit } /** @@ -129,6 +135,15 @@ abstract class Media( EMPTIED, } + /** + * Metadata associated with [Media]. + * + * @property duration Indicates the duration of the media in seconds. + */ + data class Metadata( + val duration: Double = -1.0 + ) + /** * Helper method to notify observers. */ diff --git a/components/concept/engine/src/test/java/mozilla/components/concept/engine/media/MediaTest.kt b/components/concept/engine/src/test/java/mozilla/components/concept/engine/media/MediaTest.kt index 36f690f6b43..11f116d9ce1 100644 --- a/components/concept/engine/src/test/java/mozilla/components/concept/engine/media/MediaTest.kt +++ b/components/concept/engine/src/test/java/mozilla/components/concept/engine/media/MediaTest.kt @@ -75,4 +75,5 @@ class MediaTest { private class FakeMedia : Media() { override val controller: Controller = mock() + override val metadata: Metadata = mock() } From 8538d5c6625ab0e12aaffedf34bc465c5ee21a63 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Fri, 2 Aug 2019 15:43:33 +0200 Subject: [PATCH 13/38] Closes #3795: Do not show media notification for media with very short duration. --- .../components/feature/media/MediaFeature.kt | 52 ++++++++++++------- .../feature/media/ext/MediaState.kt | 19 +++++++ .../feature/media/MediaFeatureTest.kt | 36 ++++++++++++- .../components/feature/media/MockMedia.kt | 17 ++++++ .../feature/media/focus/AudioFocusTest.kt | 2 +- .../notification/MediaNotificationTest.kt | 11 +--- .../feature/media/service/MediaServiceTest.kt | 2 +- .../media/state/MediaStateMachineTest.kt | 11 +--- 8 files changed, 107 insertions(+), 43 deletions(-) create mode 100644 components/feature/media/src/test/java/mozilla/components/feature/media/MockMedia.kt diff --git a/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt b/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt index 3e96bf2c260..ef3eb76f7b5 100644 --- a/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt +++ b/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt @@ -5,6 +5,7 @@ package mozilla.components.feature.media import android.content.Context +import mozilla.components.feature.media.ext.hasMediaWithSufficientLongDuration import mozilla.components.feature.media.service.MediaService import mozilla.components.feature.media.state.MediaState import mozilla.components.feature.media.state.MediaStateMachine @@ -22,35 +23,46 @@ import mozilla.components.feature.media.state.MediaStateMachine class MediaFeature( private val context: Context ) { - private var serviceRunning = false + private var serviceStarted = false + private var observer = object : MediaStateMachine.Observer { + override fun onStateChanged(state: MediaState) { + notifyService(state) + } + } /** * Enables the feature. */ fun enable() { - MediaStateMachine.register(MediaObserver(this)) - } + MediaStateMachine.register(observer) - internal fun startMediaService() { - MediaService.updateState(context) - serviceRunning = true + // MediaStateMachine will only notify us about state changes but not pass the current state + // to us - which might already be "playing". So let's process the current state now. + notifyService(MediaStateMachine.state) } - internal fun stopMediaService() { - if (serviceRunning) { - MediaService.updateState(context) - } - } -} + @Suppress("LongMethod") + private fun notifyService(state: MediaState) { + when (state) { + is MediaState.Playing -> { + if (state.hasMediaWithSufficientLongDuration()) { + MediaService.updateState(context) + serviceStarted = true + } + } + + is MediaState.Paused -> { + if (serviceStarted) { + MediaService.updateState(context) + } + } -internal class MediaObserver( - private val feature: MediaFeature -) : MediaStateMachine.Observer { - override fun onStateChanged(state: MediaState) { - if (state is MediaState.Playing || state is MediaState.Paused) { - feature.startMediaService() - } else if (state is MediaState.None) { - feature.stopMediaService() + is MediaState.None -> { + if (serviceStarted) { + MediaService.updateState(context) + serviceStarted = false + } + } } } } diff --git a/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt b/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt index 923f886e74d..51703005bfa 100644 --- a/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt +++ b/components/feature/media/src/main/java/mozilla/components/feature/media/ext/MediaState.kt @@ -8,6 +8,11 @@ import android.support.v4.media.session.PlaybackStateCompat import mozilla.components.concept.engine.media.Media import mozilla.components.feature.media.state.MediaState +/** + * The minimum duration (in seconds) for media so that we bother with showing a media notification. + */ +private const val MINIMUM_DURATION_SECONDS = 5 + /** * Gets the list of [Media] associated with this [MediaState]. */ @@ -62,3 +67,17 @@ internal fun MediaState.playIfPaused() { media.play() } } + +internal fun MediaState.hasMediaWithSufficientLongDuration(): Boolean { + getMedia().forEach { media -> + if (media.metadata.duration < 0) { + return true + } + + if (media.metadata.duration > MINIMUM_DURATION_SECONDS) { + return true + } + } + + return false +} diff --git a/components/feature/media/src/test/java/mozilla/components/feature/media/MediaFeatureTest.kt b/components/feature/media/src/test/java/mozilla/components/feature/media/MediaFeatureTest.kt index db63e536cbd..87e397187f3 100644 --- a/components/feature/media/src/test/java/mozilla/components/feature/media/MediaFeatureTest.kt +++ b/components/feature/media/src/test/java/mozilla/components/feature/media/MediaFeatureTest.kt @@ -10,13 +10,13 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.concept.engine.media.Media import mozilla.components.feature.media.state.MediaStateMachine -import mozilla.components.feature.media.state.MockMedia import mozilla.components.support.test.any import mozilla.components.support.test.mock import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.doReturn import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify @@ -45,6 +45,7 @@ class MediaFeatureTest { // A media object gets added to the session val media = MockMedia(Media.PlaybackState.UNKNOWN) + doReturn(30.0).`when`(media.metadata).duration session.media = listOf(media) media.playbackState = Media.PlaybackState.WAITING @@ -58,10 +59,42 @@ class MediaFeatureTest { verify(context).startService(any()) } + @Test + fun `Media with short duration will not start service`() { + val context: Context = mock() + val sessionManager = SessionManager(engine = mock()) + + MediaStateMachine.start(sessionManager) + + val feature = MediaFeature(context) + feature.enable() + + // A session gets added + val session = Session("https://www.mozilla.org") + sessionManager.add(session) + + // A media object gets added to the session + val media = MockMedia(Media.PlaybackState.UNKNOWN) + doReturn(2.0).`when`(media.metadata).duration + session.media = listOf(media) + + media.playbackState = Media.PlaybackState.WAITING + + // So far nothing has happened yet + verify(context, never()).startService(any()) + + // Media starts playing! + media.playbackState = Media.PlaybackState.PLAYING + + // Service still not started since duration is too short + verify(context, never()).startService(any()) + } + @Test fun `Media switching from playing to pause send Intent to service`() { val context: Context = mock() val media = MockMedia(Media.PlaybackState.PLAYING) + doReturn(30.0).`when`(media.metadata).duration val sessionManager = SessionManager(engine = mock()).apply { add(Session("https://www.mozilla.org").also { it.media = listOf(media) }) @@ -84,6 +117,7 @@ class MediaFeatureTest { fun `Media stopping to play will notify service`() { val context: Context = mock() val media = MockMedia(Media.PlaybackState.UNKNOWN) + doReturn(30.0).`when`(media.metadata).duration val sessionManager = SessionManager(engine = mock()).apply { add(Session("https://www.mozilla.org").also { it.media = listOf(media) }) diff --git a/components/feature/media/src/test/java/mozilla/components/feature/media/MockMedia.kt b/components/feature/media/src/test/java/mozilla/components/feature/media/MockMedia.kt new file mode 100644 index 00000000000..11a1bad77cd --- /dev/null +++ b/components/feature/media/src/test/java/mozilla/components/feature/media/MockMedia.kt @@ -0,0 +1,17 @@ +package mozilla.components.feature.media + +import mozilla.components.concept.engine.media.Media +import mozilla.components.support.test.mock + +internal class MockMedia( + initialState: PlaybackState +) : Media() { + init { + playbackState = initialState + } + + override val controller: Controller = + mock() + override val metadata: Metadata = + mock() +} \ No newline at end of file diff --git a/components/feature/media/src/test/java/mozilla/components/feature/media/focus/AudioFocusTest.kt b/components/feature/media/src/test/java/mozilla/components/feature/media/focus/AudioFocusTest.kt index a3de16f8988..60490ecff89 100644 --- a/components/feature/media/src/test/java/mozilla/components/feature/media/focus/AudioFocusTest.kt +++ b/components/feature/media/src/test/java/mozilla/components/feature/media/focus/AudioFocusTest.kt @@ -9,9 +9,9 @@ import android.media.AudioManager import androidx.test.ext.junit.runners.AndroidJUnit4 import mozilla.components.browser.session.Session import mozilla.components.concept.engine.media.Media +import mozilla.components.feature.media.MockMedia import mozilla.components.feature.media.state.MediaState import mozilla.components.feature.media.state.MediaStateMachine -import mozilla.components.feature.media.state.MockMedia import mozilla.components.support.test.any import mozilla.components.support.test.mock import mozilla.components.support.test.robolectric.testContext diff --git a/components/feature/media/src/test/java/mozilla/components/feature/media/notification/MediaNotificationTest.kt b/components/feature/media/src/test/java/mozilla/components/feature/media/notification/MediaNotificationTest.kt index e4afa2ad6d7..90667bab482 100644 --- a/components/feature/media/src/test/java/mozilla/components/feature/media/notification/MediaNotificationTest.kt +++ b/components/feature/media/src/test/java/mozilla/components/feature/media/notification/MediaNotificationTest.kt @@ -9,6 +9,7 @@ import androidx.core.app.NotificationCompat import androidx.test.ext.junit.runners.AndroidJUnit4 import mozilla.components.browser.session.Session import mozilla.components.concept.engine.media.Media +import mozilla.components.feature.media.MockMedia import mozilla.components.feature.media.R import mozilla.components.feature.media.state.MediaState import mozilla.components.support.test.mock @@ -86,16 +87,6 @@ class MediaNotificationTest { } } -internal class MockMedia( - initialState: PlaybackState -) : Media() { - init { - playbackState = initialState - } - - override val controller: Controller = mock() -} - private val Notification.text: String? get() = extras.getString(NotificationCompat.EXTRA_TEXT) diff --git a/components/feature/media/src/test/java/mozilla/components/feature/media/service/MediaServiceTest.kt b/components/feature/media/src/test/java/mozilla/components/feature/media/service/MediaServiceTest.kt index 4dca54237b8..a01d0c80266 100644 --- a/components/feature/media/src/test/java/mozilla/components/feature/media/service/MediaServiceTest.kt +++ b/components/feature/media/src/test/java/mozilla/components/feature/media/service/MediaServiceTest.kt @@ -9,8 +9,8 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.concept.engine.media.Media import mozilla.components.feature.media.MediaFeature +import mozilla.components.feature.media.MockMedia import mozilla.components.feature.media.state.MediaStateMachine -import mozilla.components.feature.media.state.MockMedia import mozilla.components.support.test.any import mozilla.components.support.test.mock import mozilla.components.support.test.robolectric.testContext diff --git a/components/feature/media/src/test/java/mozilla/components/feature/media/state/MediaStateMachineTest.kt b/components/feature/media/src/test/java/mozilla/components/feature/media/state/MediaStateMachineTest.kt index f0bb6c2ef90..553d0df24c1 100644 --- a/components/feature/media/src/test/java/mozilla/components/feature/media/state/MediaStateMachineTest.kt +++ b/components/feature/media/src/test/java/mozilla/components/feature/media/state/MediaStateMachineTest.kt @@ -7,6 +7,7 @@ package mozilla.components.feature.media.state import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.concept.engine.media.Media +import mozilla.components.feature.media.MockMedia import mozilla.components.support.test.mock import org.junit.After import org.junit.Assert.assertEquals @@ -156,13 +157,3 @@ class MediaStateMachineTest { assertEquals(MediaState.None, MediaStateMachine.state) } } - -class MockMedia( - initialState: PlaybackState -) : Media() { - init { - playbackState = initialState - } - - override val controller: Controller = mock() -} From 5b348f86a90b0ac9542d984fef062916243445d7 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Fri, 2 Aug 2019 16:08:03 +0200 Subject: [PATCH 14/38] Closes #3751: Do not set pending intent on media notification for custom tabs. --- .../media/notification/MediaNotification.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt b/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt index 062c0f06ace..22b33ae4d36 100644 --- a/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt +++ b/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt @@ -35,17 +35,24 @@ internal class MediaNotification( val data = state.toNotificationData(context) - return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) + val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setSmallIcon(data.icon) .setContentTitle(data.title) .setContentText(data.description) - .setContentIntent(pendingIntent) .setLargeIcon(data.largeIcon) .addAction(data.action) .setStyle(androidx.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSession.sessionToken) .setShowActionsInCompactView(0)) - .build() + + if (!state.isForExternalApp()) { + // We only set a content intent if this media notification is not for an "external app" + // like a custom tab. Currently we can't route the user to that particular activity: + // https://github.com/mozilla-mobile/android-components/issues/3986 + builder.setContentIntent(pendingIntent) + } + + return builder.build() } } @@ -95,3 +102,11 @@ private data class NotificationData( val largeIcon: Bitmap? = null, val action: NotificationCompat.Action ) + +private fun MediaState.isForExternalApp(): Boolean { + return when (this) { + is MediaState.Playing -> session.isCustomTabSession() + is MediaState.Paused -> session.isCustomTabSession() + is MediaState.None -> false + } +} From 31a0c2fb6b7e891fd42a40f2d4285e31408521e4 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Fri, 2 Aug 2019 16:48:22 +0200 Subject: [PATCH 15/38] Closes #3780: Re-create media channel with lower importance. --- .../feature/media/notification/MediaNotification.kt | 9 +++++---- .../media/notification/MediaNotificationChannel.kt | 11 +++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt b/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt index 22b33ae4d36..787a0e6817f 100644 --- a/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt +++ b/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotification.kt @@ -16,8 +16,6 @@ import mozilla.components.feature.media.R import mozilla.components.feature.media.service.MediaService import mozilla.components.feature.media.state.MediaState -private const val NOTIFICATION_CHANNEL_ID = "Media" - /** * Helper to display a notification for web content playing media. */ @@ -27,20 +25,23 @@ internal class MediaNotification( /** * Creates a new [Notification] for the given [state]. */ + @Suppress("LongMethod") fun create(state: MediaState, mediaSession: MediaSessionCompat): Notification { - MediaNotificationChannel.ensureChannelExists(context) + val channel = MediaNotificationChannel.ensureChannelExists(context) val intent = context.packageManager.getLaunchIntentForPackage(context.packageName) val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0) val data = state.toNotificationData(context) - val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) + val builder = NotificationCompat.Builder(context, channel) .setSmallIcon(data.icon) .setContentTitle(data.title) .setContentText(data.description) .setLargeIcon(data.largeIcon) .addAction(data.action) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setStyle(androidx.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSession.sessionToken) .setShowActionsInCompactView(0)) diff --git a/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotificationChannel.kt b/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotificationChannel.kt index 8d05394cf83..2ab0c60b346 100644 --- a/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotificationChannel.kt +++ b/components/feature/media/src/main/java/mozilla/components/feature/media/notification/MediaNotificationChannel.kt @@ -8,9 +8,11 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.os.Build +import androidx.core.app.NotificationCompat import mozilla.components.feature.media.R -private const val NOTIFICATION_CHANNEL_ID = "Media" +private const val NOTIFICATION_CHANNEL_ID = "mozac.feature.media.generic" +private const val LEGACY_NOTIFICATION_CHANNEL_ID = "Media" internal object MediaNotificationChannel { /** @@ -27,10 +29,15 @@ internal object MediaNotificationChannel { val channel = NotificationChannel( NOTIFICATION_CHANNEL_ID, context.getString(R.string.mozac_feature_media_notification_channel), - NotificationManager.IMPORTANCE_DEFAULT + NotificationManager.IMPORTANCE_LOW ) + channel.setShowBadge(false) + channel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC notificationManager.createNotificationChannel(channel) + + // We can't just change a channel. So we had to re-create the channel with a new name. + notificationManager.deleteNotificationChannel(LEGACY_NOTIFICATION_CHANNEL_ID) } return NOTIFICATION_CHANNEL_ID From bfa571442675e4d7991c79a11cae1ad169633710 Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Fri, 9 Aug 2019 13:39:26 -0700 Subject: [PATCH 16/38] For #4083: make findSessionById thread-safe --- .../components/browser/session/LegacySessionManager.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt b/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt index ff257e56d48..b948d096dbc 100644 --- a/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt +++ b/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt @@ -22,6 +22,8 @@ class LegacySessionManager( val engine: Engine, delegate: Observable = ObserverRegistry() ) : Observable by delegate { + // It's important that any access to `values` is synchronized; + @GuardedBy("values") private val values = mutableListOf() @GuardedBy("values") @@ -522,7 +524,9 @@ class LegacySessionManager( * Finds and returns the session with the given id. Returns null if no matching session could be * found. */ - fun findSessionById(id: String): Session? = values.find { session -> session.id == id } + fun findSessionById(id: String): Session? = synchronized(values) { + values.find { session -> session.id == id } + } /** * Informs this [SessionManager] that the OS is in low memory condition so it From 56cbebd3e3914df3328b0815d8d0bac276f3cab4 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Fri, 9 Aug 2019 14:35:28 +0200 Subject: [PATCH 17/38] Import strings from android-l10n State: mozilla-l10n/android-l10n@ab580f757c76ed323a5c81ef92e62c9253efe673 --- .../src/main/res/values-cs/strings.xml | 10 + .../src/main/res/values-es-rAR/strings.xml | 10 + .../src/main/res/values-fi/strings.xml | 10 + .../src/main/res/values-pa-rIN/strings.xml | 10 + .../src/main/res/values-ca/strings.xml | 13 + .../src/main/res/values-cs/strings.xml | 259 ++++++++++++++++++ .../src/main/res/values-es-rAR/strings.xml | 229 ++++++++++++++++ .../src/main/res/values-eu/strings.xml | 29 ++ .../src/main/res/values-fi/strings.xml | 53 ++++ .../src/main/res/values-in/strings.xml | 29 ++ .../src/main/res/values-pa-rIN/strings.xml | 85 ++++++ .../src/main/res/values-sk/strings.xml | 145 +++++++++- .../src/main/res/values-cs/strings.xml | 8 + .../src/main/res/values-es-rAR/strings.xml | 8 + .../src/main/res/values-fi/strings.xml | 8 + .../src/main/res/values-pa-rIN/strings.xml | 8 + .../src/main/res/values-cs/strings.xml | 11 + .../src/main/res/values-es-rAR/strings.xml | 11 + .../src/main/res/values-eu/strings.xml | 6 +- .../src/main/res/values-fi/strings.xml | 11 + .../src/main/res/values-pa-rIN/strings.xml | 9 + .../src/main/res/values-cs/strings.xml | 25 ++ .../src/main/res/values-es-rAR/strings.xml | 25 ++ .../src/main/res/values-eu/strings.xml | 25 ++ .../src/main/res/values-fi/strings.xml | 25 ++ .../src/main/res/values-pa-rIN/strings.xml | 25 ++ .../src/main/res/values-cs/strings.xml | 5 + .../src/main/res/values-es-rAR/strings.xml | 5 + .../src/main/res/values-eu/strings.xml | 5 + .../src/main/res/values-fi/strings.xml | 5 + .../src/main/res/values-pa-rIN/strings.xml | 5 + .../src/main/res/values-cs/strings.xml | 19 ++ .../src/main/res/values-es-rAR/strings.xml | 18 ++ .../src/main/res/values-eu/strings.xml | 18 ++ .../src/main/res/values-fi/strings.xml | 18 ++ .../src/main/res/values-pa-rIN/strings.xml | 18 ++ .../src/main/res/values-cs/strings.xml | 24 ++ .../src/main/res/values-es-rAR/strings.xml | 24 ++ .../src/main/res/values-eu/strings.xml | 24 ++ .../src/main/res/values-fi/strings.xml | 17 ++ .../src/main/res/values-pa-rIN/strings.xml | 21 ++ .../media/src/main/res/values-cs/strings.xml | 12 + .../src/main/res/values-es-rAR/strings.xml | 12 + .../media/src/main/res/values-eu/strings.xml | 12 + .../media/src/main/res/values-fi/strings.xml | 12 + .../src/main/res/values-pa-rIN/strings.xml | 13 + .../src/main/res/values-cs/strings.xml | 28 ++ .../src/main/res/values-es-rAR/strings.xml | 28 ++ .../src/main/res/values-eu/strings.xml | 28 ++ .../src/main/res/values-fi/strings.xml | 21 ++ .../src/main/res/values-pa-rIN/strings.xml | 28 ++ .../src/main/res/values-cs/strings.xml | 29 ++ .../src/main/res/values-es-rAR/strings.xml | 29 ++ .../src/main/res/values-eu/strings.xml | 29 ++ .../src/main/res/values-fi/strings.xml | 16 ++ .../src/main/res/values-pa-rIN/strings.xml | 19 ++ .../src/main/res/values-cs/strings.xml | 34 +++ .../src/main/res/values-es-rAR/strings.xml | 34 +++ .../src/main/res/values-eu/strings.xml | 27 ++ .../src/main/res/values-fi/strings.xml | 24 ++ .../src/main/res/values-pa-rIN/strings.xml | 34 +++ .../tabs/src/main/res/values-cs/strings.xml | 5 + .../src/main/res/values-es-rAR/strings.xml | 5 + .../tabs/src/main/res/values-fi/strings.xml | 5 + .../src/main/res/values-pa-rIN/strings.xml | 5 + .../crash/src/main/res/values-cs/strings.xml | 21 ++ .../src/main/res/values-es-rAR/strings.xml | 21 ++ .../crash/src/main/res/values-fi/strings.xml | 19 ++ .../crash/src/main/res/values-in/strings.xml | 6 + .../src/main/res/values-pa-rIN/strings.xml | 22 ++ .../ktx/src/main/res/values-cs/strings.xml | 5 + .../src/main/res/values-es-rAR/strings.xml | 5 + .../ktx/src/main/res/values-fi/strings.xml | 5 + .../src/main/res/values-pa-rIN/strings.xml | 5 + 74 files changed, 1909 insertions(+), 2 deletions(-) create mode 100644 components/browser/engine-system/src/main/res/values-cs/strings.xml create mode 100644 components/browser/engine-system/src/main/res/values-es-rAR/strings.xml create mode 100644 components/browser/engine-system/src/main/res/values-fi/strings.xml create mode 100644 components/browser/engine-system/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/browser/errorpages/src/main/res/values-ca/strings.xml create mode 100644 components/browser/errorpages/src/main/res/values-cs/strings.xml create mode 100644 components/browser/errorpages/src/main/res/values-es-rAR/strings.xml create mode 100644 components/browser/errorpages/src/main/res/values-fi/strings.xml create mode 100644 components/browser/errorpages/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/browser/toolbar/src/main/res/values-cs/strings.xml create mode 100644 components/browser/toolbar/src/main/res/values-es-rAR/strings.xml create mode 100644 components/browser/toolbar/src/main/res/values-fi/strings.xml create mode 100644 components/browser/toolbar/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/app-links/src/main/res/values-cs/strings.xml create mode 100644 components/feature/app-links/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/app-links/src/main/res/values-fi/strings.xml create mode 100644 components/feature/app-links/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/contextmenu/src/main/res/values-cs/strings.xml create mode 100644 components/feature/contextmenu/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/contextmenu/src/main/res/values-eu/strings.xml create mode 100644 components/feature/contextmenu/src/main/res/values-fi/strings.xml create mode 100644 components/feature/contextmenu/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/customtabs/src/main/res/values-cs/strings.xml create mode 100644 components/feature/customtabs/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/customtabs/src/main/res/values-eu/strings.xml create mode 100644 components/feature/customtabs/src/main/res/values-fi/strings.xml create mode 100644 components/feature/customtabs/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/downloads/src/main/res/values-cs/strings.xml create mode 100644 components/feature/downloads/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/downloads/src/main/res/values-eu/strings.xml create mode 100644 components/feature/downloads/src/main/res/values-fi/strings.xml create mode 100644 components/feature/downloads/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/findinpage/src/main/res/values-cs/strings.xml create mode 100644 components/feature/findinpage/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/findinpage/src/main/res/values-eu/strings.xml create mode 100644 components/feature/findinpage/src/main/res/values-fi/strings.xml create mode 100644 components/feature/findinpage/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/media/src/main/res/values-cs/strings.xml create mode 100644 components/feature/media/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/media/src/main/res/values-eu/strings.xml create mode 100644 components/feature/media/src/main/res/values-fi/strings.xml create mode 100644 components/feature/media/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/prompts/src/main/res/values-cs/strings.xml create mode 100644 components/feature/prompts/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/prompts/src/main/res/values-eu/strings.xml create mode 100644 components/feature/prompts/src/main/res/values-fi/strings.xml create mode 100644 components/feature/prompts/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/readerview/src/main/res/values-cs/strings.xml create mode 100644 components/feature/readerview/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/readerview/src/main/res/values-eu/strings.xml create mode 100644 components/feature/readerview/src/main/res/values-fi/strings.xml create mode 100644 components/feature/readerview/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/sitepermissions/src/main/res/values-cs/strings.xml create mode 100644 components/feature/sitepermissions/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/sitepermissions/src/main/res/values-fi/strings.xml create mode 100644 components/feature/sitepermissions/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/feature/tabs/src/main/res/values-cs/strings.xml create mode 100644 components/feature/tabs/src/main/res/values-es-rAR/strings.xml create mode 100644 components/feature/tabs/src/main/res/values-fi/strings.xml create mode 100644 components/feature/tabs/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/lib/crash/src/main/res/values-cs/strings.xml create mode 100644 components/lib/crash/src/main/res/values-es-rAR/strings.xml create mode 100644 components/lib/crash/src/main/res/values-fi/strings.xml create mode 100644 components/lib/crash/src/main/res/values-pa-rIN/strings.xml create mode 100644 components/support/ktx/src/main/res/values-cs/strings.xml create mode 100644 components/support/ktx/src/main/res/values-es-rAR/strings.xml create mode 100644 components/support/ktx/src/main/res/values-fi/strings.xml create mode 100644 components/support/ktx/src/main/res/values-pa-rIN/strings.xml diff --git a/components/browser/engine-system/src/main/res/values-cs/strings.xml b/components/browser/engine-system/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..bc5b5608f0c --- /dev/null +++ b/components/browser/engine-system/src/main/res/values-cs/strings.xml @@ -0,0 +1,10 @@ + + + + Sdělení stránky %1$s: + + %2$s požaduje vaše uživatelské jméno a heslo. Sdělení serveru: „%1$s“ + + %1$s požaduje vaše uživatelské jméno a heslo. + diff --git a/components/browser/engine-system/src/main/res/values-es-rAR/strings.xml b/components/browser/engine-system/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..8f0dde846d6 --- /dev/null +++ b/components/browser/engine-system/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,10 @@ + + + + La página en %1$s dice: + + %2$s está pidiendo tu nombre de usuario y contraseña. El sitio dice: “%1$s” + + %1$s te está pidiendo tu nombre de usuario y contraseña. + diff --git a/components/browser/engine-system/src/main/res/values-fi/strings.xml b/components/browser/engine-system/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..af33a323c4f --- /dev/null +++ b/components/browser/engine-system/src/main/res/values-fi/strings.xml @@ -0,0 +1,10 @@ + + + + Sivu osoitteessa %1$s sanoo: + + %2$s pyytää käyttäjätunnusta ja salasanaa. Sivusto sanoo: ”%1$s” + + %1$s pyytää käyttäjätunnusta ja salasanaa. + diff --git a/components/browser/engine-system/src/main/res/values-pa-rIN/strings.xml b/components/browser/engine-system/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..59c19abe0c6 --- /dev/null +++ b/components/browser/engine-system/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,10 @@ + + + + %1$s ਸਫ਼ੇ ਤੋਂ: + + %2$s ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ-ਨਾਂ ਅਤੇ ਪਾਸਵਰਡ ਦੀ ਮੰਗ ਕਰ ਰਹੀ ਹੈ। ਸਾਈਟ ਕਹਿੰਦੀ ਹੈ: “%1$s” + + %1$s ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ-ਨਾਂ ਅਤੇ ਪਾਸਵਰਡ ਦੀ ਮੰਗ ਕਰ ਰਹੀ ਹੈ। + diff --git a/components/browser/errorpages/src/main/res/values-ca/strings.xml b/components/browser/errorpages/src/main/res/values-ca/strings.xml new file mode 100644 index 00000000000..780fa516978 --- /dev/null +++ b/components/browser/errorpages/src/main/res/values-ca/strings.xml @@ -0,0 +1,13 @@ + + + + + Torna-ho a provar + + + El port s\'ha restringit per motius de seguretat + + + L’adreça no és vàlida + + diff --git a/components/browser/errorpages/src/main/res/values-cs/strings.xml b/components/browser/errorpages/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..fd3f67d78ff --- /dev/null +++ b/components/browser/errorpages/src/main/res/values-cs/strings.xml @@ -0,0 +1,259 @@ + + + + Chyba při načítání stránky + + + Zkusit znovu + + + Přejít zpět + + + Nepodařilo se dokončit požadavek + + Další informace o této chybě nejsou bohužel dostupné.

+ ]]>
+ + + Chyba zabezpečeného spojení + + +
  • Požadovanou stránku nelze zobrazit, protože nelze ověřit autenticitu přijatých dat.
  • +
  • Kontaktujte prosím vlastníky webového serveru a informujte je o tomto problému.
  • + + ]]>
    + + + Chyba zabezpečeného spojení + + +
  • Tato chyba může být způsobena chybnou konfigurací serveru nebo někým, +kdo se snaží vydávat za server.
  • +
  • Pokud jste se k tomuto serveru připojili úspěšně již v minulosti, je možná chyba jenom dočasná, a můžete to zkusit znovu později.
  • + + ]]>
    + + + Spojení bylo přerušeno + + Podařilo se připojit k serveru, ale spojení bylo v průběhu přenosu přerušeno. Opakujte akci.

    +
      +
    • Stránka může být dočasně nedostupná nebo zaneprázdněná. Zkuste to znovu za pár okamžiků.
    • +
    • Pokud nemůžete načíst žádnou stránku, zkontrolujte svá mobilní data nebo Wi-Fi připojení.
    • +
    + ]]>
    + + + Vypršel čas spojení + + Požadovaný server neodpověděl na požadavek o připojení a prohlížeč ukončil čekání na tuto odpověď.

    +
      +
    • Server může být velmi vytížen; Opakujte akci později.
    • Je možné, že se jedná o síťový problém mezi vaším počítačem a serverem.
    • +
    • Pokud problém přetrvává, poraďte se se správcem vaší sítě, nebo poskytovatelem připojení k internetu.
    • +
    + ]]>
    + + + Nelze se připojit + + +
  • Stránka může být dočasně nedostupná nebo zaneprázdněná. Zkuste to znovu za pár okamžiků.
  • +
  • Pokud nemůžete načíst žádnou stránku, zkontrolujte svá mobilní data nebo Wi-Fi připojení.
  • + + ]]>
    + + + Neplatná odpověď serveru + + Server odpověděl na požadavek neočekávaným způsobem a prohlížeč tak nemohl pokračovat.

    + ]]>
    + + + Smyčka při přesměrování + + Prohlížeč ukončil spojení, protože server přesměrovává požadavky na tuto adresu sám na sebe, a to takovým způsobem, který zabraňuje jejich dokončení.

    +
      +
    • Je možné, že stránka vyžaduje ukládání cookies, které máte zakázané nebo je pro tento server blokujete.
    • +
    • Většinou se ale jedná o problém konfigurace serveru a není to tak problém vašeho počítače.
    • +
    + ]]>
    + + + Režim offline + + Prohlížeč je teď v režimu offline a k požadované položce se nelze připojit.

    +
      +
    • Je počítač připojen k funkční síti?
    • +
    • Pro přechod do režimu online a obnovení stránky klepněte na tlačítko „Zkusit znovu“.
    • +
    + ]]>
    + + + Omezení přístupu na port + + V požadované adrese (URL) byl zadán port (např. mozilla.org:80 pro port 80 na serveru mozilla.org), který se obvykle používá pro jiné internetové služby než je prohlížení webových stránek. Prohlížeč zrušil požadavek z důvodů vaší ochrany.

    + ]]>
    + + + Spojení přerušeno + + Spojení bylo v průběhu otevírání komunikačního kanálu se serverem neočekávaně přerušeno. Opakujte akci.

    +
      +
    • Server je dočasně nedostupný. Zkuste to prosím znovu za chvíli.
    • +
    • Pokud nemůžete načíst žádnou stránku, zkontrolujte svá mobilní data nebo Wi-Fi připojení.
    • +
    + ]]>
    + + + Nebezpečný typ souboru + + +
  • Kontaktujte prosím vlastníky webového serveru a informujte je o tomto problému.
  • + + ]]>
    + + + Chyba v obsahu stránky + + Požadovanou stránku nelze zobrazit, protože při přenosu dat došlo k chybě.

    +
      +
    • Kontaktujte prosím vlastníky webového serveru a informujte je o tomto problému.
    • +
    + ]]>
    + + + Pád obsahu + Požadovanou stránku nelze zobrazit, protože při přenosu dat došlo k chybě.

    +
      +
    • Kontaktujte prosím vlastníky webového serveru a informujte je o tomto problému.
    • +
    + ]]>
    + + + Chyba znakové sady obsahu + Požadovanou stránku nelze zobrazit, protože používá neplatný či nepodporovaný způsob komprese dat.

    +
      +
    • Kontaktujte prosím vlastníky webového serveru a informujte je o tomto problému.
    • +
    + ]]>
    + + + Adresa nenalezena + + URL adresa neodpovídá známému serveru a nelze ji načíst.

    +
      +
    • Zkontrolujte prosím, že jste adresu napsali správně (např. že neobsahuje + ww.example.com místo www.example.com
    • +
    • Pokud nemůžete načíst žádnou stránku, zkontrolujte svá mobilní data nebo Wi-Fi připojení.
    • +
    + ]]>
    + + + Neplatná adresa + Adresa (URL) není platná a nelze ji načíst. Zkontrolujte prosím, že je adresa napsána správně.

    + ]]>
    + + Neplatná adresa + + +
  • Webové adresy jsou obvykle psány jako http://www.example.com/
  • +
  • Ujistěte se, že používáte běžná lomítka (tj. /).
  • + + ]]>
    + + + Neznámý protokol + Adresu (URL) určuje protokol (např. wxyz://), který nebyl prohlížečem rozpoznán, a proto se k ní nemůže korektně připojit.

    +
      +
    • Zkoušíte přistupovat k multimédiím či jiné netextové službě? Podívejte se, jaké další věci stránka vyžaduje.
    • +
    • Některé protokoly mohou vyžadovat software třetích stran nebo zásuvné moduly dříve, než je prohlížeč může rozpoznat.
    • +
    + ]]>
    + + + Soubor nenalezen + +
  • Je možné, že byl smazán, přejmenován nebo přesunut.
  • +
  • Zkontrolujte prosím, že je adresa napsána správně, a to včetně velikosti písmen.
  • +
  • Jste-li autorem tohoto souboru, ověřte, že daný soubor na serveru existuje a že má příslušná práva na zobrazení.
  • + + ]]>
    + + + Přístup k souboru byl odepřen + +
  • Možná byl smazán, přesunut nebo jeho oprávnění zabraňují přístupu.
  • + + ]]>
    + + + Proxy server odmítl spojení + Prohlížeč je nakonfigurován k použití proxy serveru, který odmítl spojení.

    +
      +
    • Zkontrolujte v prohlížeči nastavení proxy serveru a opakujte akci.
    • +
    • Je možné, že proxy server nepovoluje připojení z vaší sítě.
    • +
    • Pokud problém přetrvává, poraďte se se správcem vaší sítě, nebo poskytovatelem připojení k internetu.
    • +
    + ]]>
    + + + Proxy server nenalezen + Prohlížeč je nakonfigurován k použití proxy serveru, který nemohl být nalezen.

    +
      +
    • Zkontrolujte v prohlížeči nastavení proxy serveru a opakujte akci.
    • +
    • Pokud problém přetrvává, poraďte se se správcem vaší sítě, nebo poskytovatelem připojení k internetu.
    • +
    + ]]>
    + + + Problém se škodlivým softwarem + + Stránka %1$s byla nahlášena jako útočná a byla zablokována na základě vašeho bezpečnostního nastavení.

    + ]]>
    + + + Problém s nežádoucí webovou stránkou + + Stránka %1$s byla nahlášena jako stránka s nežádoucím softwarem a byla zablokována na základě vašeho bezpečnostního nastavení.

    + ]]>
    + + + Problém se škodlivou stránkou + + Stránka %1$s byla nahlášena jako útočná a byla zablokována na základě vašeho bezpečnostního nastavení.

    + ]]>
    + + + Problém s klamavou stránkou + + Tato webová stránka na serveru %1$s byla nahlášena jako klamavá a byla zablokována na základě vašeho bezpečnostního nastavení.

    + ]]>
    +
    diff --git a/components/browser/errorpages/src/main/res/values-es-rAR/strings.xml b/components/browser/errorpages/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..96029c6568a --- /dev/null +++ b/components/browser/errorpages/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,229 @@ + + + + Problema al cargar la página + + + Probar de nuevo + + + Retroceder + + + No se puede completar el pedido + + En este momento no hay información adicional disponible para este problema o error.

    + ]]>
    + + + Falló la conexión segura + + +
  • La página que estás intentando ver no se puede mostrar porque no se pudo verificar la autenticidad de los datos recibidos.
  • +
  • Por favor contactate con los propietarios del sitio web para informarles de este problema.
  • + ]]>
    + + + Falló la conexión segura + + +
  • Esto podría ser un problema con la configuración del servidor o podría ser alguien tratando de hacerse pasar por el servidor.
  • +
  • Si te conectaste sin problemas a este servidor en el pasado, el error puede ser temporal y podés probar de nuevo más tarde.
  • + +]]>
    + + + Se interrumpió la conexión + + El navegador se conectó con éxito, pero se interrumpió la conexión mientras se transfería la información. Volvé a probar.

    +
      +
    • El sitio podría no estar disponible temporalmente o estar demasiado ocupado. Volvé a probar en unos minutos.
    • +
    • Si no podés cargar ninguna página, revisa la conexión wifi o de datos de tu dispositivo móvil.
    • +
    + ]]>
    + + + La conexión tardó demasiado tiempo + + El sitio solicitado no respondió a una pedido de conexión y el navegador dejó de esperar una respuesta.

    +
      +
    • ¿El servidor podría estar experimentando una alta demanda o un corte temporal? Volvé a probar más tarde.
    • +
    • ¿No podés navegar por otros sitios? Comprobá la conexión de red del equipo.
    • +
    • ¿Tu red o equipo está protegido por un firewall o un proxy? Una configuración incorrecta puede interferir con la navegación web.
    • +
    • ¿Todavía tenés problemas? Consultá con el administrador de la red o el proveedor de Internet para obtener asistencia técnica.
    • +
    + ]]>
    + + + No se puede conectar + + + +
  • El sitio puede estar temporariamente inaccesible o demasiado ocupado. Intentá nuevamente en un rato.
  • +
  • Si no podés cargar ninguna página, verificá la conexión de datos o Wi-Fi de tu dispositivo.
  • + ]]>
    + + + Respuesta inesperada del servidor + + El sitio respondió al pedido de la red de una forma inesperada y el navegador no puede continuar.

    ]]>
    + + + La página no se redirecciona correctamente + + + El navegador dejó de tratar de transferir el ítem solicitado. El sitio está redirigiendo el pedido en una manera que nunca se completará.

    +
      +
    • ¿Deshabilitaste o bloqueaste cookies requeridas por este sitio?
    • +
    • Si aceptar las cookies del sitio no resuelve el problema, seguramente es un problema de configuración del servidor y no de tu computadora.
    • + +
    + ]]>
    + + + Modo sin conexión + + + El navegador está funcionando en el modo sin conexión y no puede conectarse al ítem solicitado.

    • ¿La computadora está conectada a una red activa?
    • Presioná “Intentar de nuevo” para volver al modo con conexión y recargar la página.
    ]]>
    + + + Restricción del puerto por razones de seguridad + + La dirección solicitada especificaba un puerto (p. ej., mozilla.org:80 para el puerto 80 de mozilla.org) que suele usarse para propósitos distintos a navegar por Internet. El navegador canceló la solicitud para tu protección y seguridad.

    + ]]>
    + + + Se restableció la conexión + + + ]]> + + + Tipo de archivo no seguro + + + +
  • Contactate con los propietarios del sitio web para informarles de este problema.
  • + + ]]>
    + + + Error de contenido corrupto + + + La página que estás intentando ver no puede mostrarse porque se detectó un error en la transmisión de los datos.

    +
      +
    • Contactate con los propietarios del sitio web para informarles de este problema.
    • +
    + ]]>
    + + + El contenido falló + + La página que estás tratando de ver no puede ser mostrada porque se detectó un error en la transmisión de datos.

    +
      +
    • Contactá a los dueños del sitio web para informarles sobre este problema.
    • +
    + ]]>
    + + + Error de codificación de contenido + + La página que estás tratando de ver no puede mostrarse porque usa una forma de compresión inválida o no soportada.

    +
      +
    • Contactá a los dueños del sitio web para informarles sobre este problema.
    • + +
    + ]]>
    + + + No se encontró la dirección + + + El navegador no pudo encontrar el servidor de la dirección provista.

    +
      +
    • Verificá si la dirección no tiene errores de tipeo como + ww.example.com en lugar de + www.example.com.
    • +
    • Si no podés cargar ninguna página, verificá la conexión de datos o Wi-Fi de tu dispositivo.
    • +
    + ]]>
    + + + La dirección no es válida + La dirección provista no tiene un formato reconocible. Mirá si no hay errores en la barra de direcciones e intentá nuevamente.

    + ]]>
    + + La dirección no es válida + + + +
  • Usualmente las direcciones web se escriben como http://www.example.com/
  • +
  • Asegurate de estar usando las barras correctas (ej: /).
  • + + ]]>
    + + + Protocolo desconocido + + La dirección especifica un protocolo (ej: wxyz://) que el navegador no reconoce, así que no puede conectarse adecuadamente al sitio.

    +
      +
    • ¿Estás tratando de acceder a multimedia o a otros servicios que no son de texto? Verifiá el sitio para requerimientos extra.
    • +
    • Algunos protocolos pueden requerir software de terceros o plugins antes que el navegador pueda reconocerlos.
    • +
    + ]]>
    + + + Archivo no encontrado + + +
  • ¿Puede ser que el ítem haya sido renombrado, removido o reubicado?
  • +
  • ¿Hay un error de ortografía, mayúsculas o algún error tipográfico en la dirección?
  • +
  • ¿Tenés suficientes permisos de acceso al ítem solicitado?
  • + + ]]>
    + + + Se denegó el acceso al archivo + + +
  • Puede haber sido eliminado, movido o los permisos pueden evitar el acceso.
  • + + ]]>
    + + + El servidor proxy rechazó la conexión + + + No se encontró el servidor proxy + + El navegador está configurado para usar un servidor proxy, pero el proxy no se encontró el servidor.

    • ¿La configuración del proxy del navegador es correcta? Verificá la configuración y probá de nuevo.
    • ¿La computadora está conectada a una red activa?
    • ¿Todavía tenés problemas? Consultá con tu administrador de red o tu proveedor de Internet para recibir asistencia.
    ]]>
    + + + Problema del sitio con contenido malicioso + + + Problema de sitio no deseado + + + Problema de sitio dañino + + + El sitio es engañoso +
    diff --git a/components/browser/errorpages/src/main/res/values-eu/strings.xml b/components/browser/errorpages/src/main/res/values-eu/strings.xml index 04975de73bc..cf27173a0b9 100644 --- a/components/browser/errorpages/src/main/res/values-eu/strings.xml +++ b/components/browser/errorpages/src/main/res/values-eu/strings.xml @@ -42,6 +42,15 @@ Konexioa eten egin da + + Nabigatzaileak konexioa ondo sortu du, baina datuak jasotzen ari zela transferentzia eten egin da. Mesedez, saiatu berriro.

    +
      +
    • Gunea une batez desgaituta edo oso lanpetuta egon daiteke. Saiatu berriro minutu batzuen buruan.
    • +
    • Ezin baduzu beste orririk kargatu, egiaztatu zure gailuaren datu- edo WiFi-konexioa.
    • +
    + ]]>
    + Konexioaren denbora-muga gainditu da @@ -107,6 +116,15 @@ Konexioa berrezarri egin da + + Sareko lotura eten egin da konexioa negoziatzerakoan. Mesedez saiatu berriro.

    +
      +
    • Gunea une batez desgaituta edo oso lanpetuta egon daiteke. Saiatu berriro minutu batzuen buruan.
    • +
    • Ezin baduzu beste orririk kargatu, egiaztatu zure gailuaren datu- edo WiFi-konexioa.
    • +
    + ]]>
    + Fitxategi mota ez-segurua @@ -127,6 +145,8 @@ ]]>
    + + Edukiak huts egin du Ikusten saiatzen ari zaren orria ezin da erakutsi errore bat detektatu delako datu-transmisioan.

      @@ -147,6 +167,15 @@ Helbidea ez da aurkitu + + Nabigatzaileak ezin du ostalariko zerbitzaria aurkitu emandako helbidean.

      +
        +
      • Helbidea ondo begiratu mota honetako erroreak ekiditeko: ww.adibidea.eus www.adibidea.eus-en ordez.
      • +
      • Ezin baduzu inolako orririk kargatu, begiratu zure gailuaren datu- edo WiFi-konexioa.
      • +
      + ]]>
      + Helbide baliogabea + + + Ongelma sivua ladatessa + + + Yritä uudelleen + + + Siirry takaisin + + + Pyyntöä ei voi suorittaa + + + Suojattu yhteys epäonnistui + + + Suojattu yhteys epäonnistui + + + Yhteys keskeytettiin + + + Yhteys aikakatkaistiin + + + Yhdistäminen ei onnistu + + + Odottamaton vastaus palvelimelta + + + Yhteydetön tila + + + Sisältö kaatui + + + Osoitetta ei löytynyt + + + Virheellinen osoite + + Osoite ei ole kelvollinen + + + Tiedostoa ei löydy + + + Välityspalvelinta ei löytynyt + + diff --git a/components/browser/errorpages/src/main/res/values-in/strings.xml b/components/browser/errorpages/src/main/res/values-in/strings.xml index 684c1037381..f34a663fbea 100644 --- a/components/browser/errorpages/src/main/res/values-in/strings.xml +++ b/components/browser/errorpages/src/main/res/values-in/strings.xml @@ -32,15 +32,35 @@ Sambungan Aman Gagal + + +
    • Mungkin terjadi masalah dengan konfigurasi server, atau bisa saja seseorang berusaha menyamar menjadi server.
    • +
    • Jika Anda pernah tersambung dengan baik, kesalahan ini mungkin hanya sementara dan Anda dapat mencoba lagi nanti.
    • +
    + ]]>
    + Sambungan terputus + + Peramban terhubung dengan sukses, namun koneksi terganggu saat mentransfer informasi. Silakan coba lagi.

    +
      +
    • Situs ini mungkin sementara tidak sedia atau sedang sibuk. Coba lagi dalam beberapa saat.
    • +
    • Jika Anda tidak dapat memuat laman apapun, periksa koneksi data atau Wi-Fi pada perangkat Anda.
    • +
    + ]]>
    + Tenggang waktu tersambung habis Tidak dapat tersambung + + Respon tidak terduga dari server + Laman tidak teralihkan dengan benar @@ -67,6 +87,9 @@ ]]>
    + + Konten macet + Kesalahan Pengodean Isi (Content Encoding) @@ -105,6 +128,12 @@ Masalah situs malware + + Masalah situs yang tidak diinginkan + + + Masalah situs berbahaya + Masalah situs tipuan diff --git a/components/browser/errorpages/src/main/res/values-pa-rIN/strings.xml b/components/browser/errorpages/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..fc363e8091f --- /dev/null +++ b/components/browser/errorpages/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,85 @@ + + + + ਸਫ਼ਾ ਲੋਡ ਕਰਨ ‘ਚ ਸਮੱਸਿਆ + + + ਮੁੜ-ਕੋਸ਼ਿਸ਼ ਕਰੋ + + + ਪਿੱਛੇ ਜਾਓ + + + ਬੇਨਤੀ ਪੂਰੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ + + + ਇਸ ਸਮੱਸਿਆ ਬਾਰੇ ਵਧੀਕ ਜਾਣਕਾਰੀ ਜਾਂ ਗਲਤੀ ਇਸ ਵੇਲੇ ਉਪਲਬੱਧ ਨਹੀਂ ਹੈ।

    + ]]>
    + + + ਸੁਰੱਖਿਅਤ ਕਨੈਕਸ਼ਨ ਅਸਫ਼ਲ ਹੈ + + + ਸੁਰੱਖਿਅਤ ਕਨੈਕਸ਼ਨ ਅਸਫ਼ਲ ਹੈ + + + ਕਨੈਕਸ਼ਨ ‘ਚ ਰੁਕਾਵਟ ਆਈ ਸੀ + + + ਕਨੈਕਸ਼ਨ ਲਈ ਸਮਾਂ ਸਮਾਪਤ ਹੈ + + + ਕਨੈਕਟ ਕਰਨ ਲਈ ਅਸਮਰੱਥ ਹੈ + + + ਸਰਵਰ ਤੋਂ ਅਣਚਿਤਵਿਆ ਜਵਾਬ ਮਿਲਿਆ + + + ਸਫ਼ੇ ਲਈ ਠੀਕ ਤਰ੍ਹਾਂ ਮੁੜ-ਦਿਸ਼ਾ ਪਰਿਵਰਤਨ ਨਹੀਂ ਕੀਤਾ ਗਿਆ + + + ਆਫ਼ਲਾਈਨ ਢੰਗ + + + ਸੁਰੱਖਿਆ ਕਾਰਨਾਂ ਕਰਕੇ ਪੋਰਟ ਉੱਤੇ ਪਾਬੰਦੀ ਲਗਾਈ + + + ਕਨੈਕਸ਼ਨ ਮੁੜ-ਸੈੱਟ ਕੀਤਾ ਗਿਆ ਸੀ + + + ਅਸੁਰੱਖਿਅਤ ਫਾਈਲ ਕਿਸਮ + + +
  • ਇਸ ਸਮੱਸਿਆ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦੇਣ ਲਈ ਵੈੱਬਸਾਈਟ ਦੇ ਮਾਲਕਾਂ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।
  • + + ]]>
    + + + ਨਿਕਾਰਾ ਹੋਈ ਦੀ ਸਮੱਗਰੀ ਗਲਤੀ + + + ਸਮੱਗਰੀ ਕਰੈਸ਼ ਹੋਈ + + + ਸਮੱਗਰੀ ਇੰਕੋਡਿੰਗ ਗਲਤੀ + + + ਸਿਰਨਾਵਾਂ ਨਹੀਂ ਲੱਭਿਆ + + + ਅਢੁੱਕਵਾਂ ਸਿਰਨਾਵਾਂ + + ਸਿਰਨਾਵਾਂ ਢੁੱਕਵਾਂ ਨਹੀਂ ਹੈ + + + ਅਣਪਛਾਤਾ ਪਰੋਟੋਕਾਲ + + + ਫਾਈਲ ਨਹੀਂ ਲੱਭੀ + + + ਫਾਈਲ ਲਈ ਪਹੁੰਚ ਤੋਂ ਨਾਂਹ ਕੀਤੀ + +
    diff --git a/components/browser/errorpages/src/main/res/values-sk/strings.xml b/components/browser/errorpages/src/main/res/values-sk/strings.xml index 8ca38fb60d6..c0ea52fca6b 100644 --- a/components/browser/errorpages/src/main/res/values-sk/strings.xml +++ b/components/browser/errorpages/src/main/res/values-sk/strings.xml @@ -39,6 +39,15 @@ Pripojenie bolo prerušené + + Prehliadač sa úspešne pripojil k serveru, ale spojenie bolo v priebehu prenosu údajov prerušené. Prosím, skúste to znova.

    +
      +
    • Stránka môže byť dočasne nedostupná alebo zaneprázdnená. Skúste to znova neskôr.
    • +
    • Ak sa vám nedarí načítať žiadnu stránku, skontrolujte pripojenie svojho zariadenia na internet.
    • +
    + ]]>
    + Čas pripojenia vypršal @@ -85,12 +94,35 @@ Režim offline + + Prehliadač je momentálne v režime offline a nemôže sa pripojiť na požadovaný server.

    +
      +
    • Je počítač pripojený k aktívnej sieti?
    • +
    • Kliknutím na tlačidlo „Skúsiť znova“ prejdete do režimu online a opätovne načítate obsah stránky.
    • +
    + ]]>
    + Bezpečnostné obmedzenie prístupu na port + + Zadaná adresa (URL) špecifikovala port (napr. mozilla.org:80 je port 80 na mozilla.org), ktorý je normálne určený na iné služby ako prehliadanie webu. Prehliadač požiadavku kvôli vašej ochrane a bezpečnosti neakceptoval.

    + ]]>
    + Výpadok pripojenia + + Spojenie bolo v priebehu otvárania komunikačného kanála so serverom nečakane prerušené. Skúste to znova

    +
      +
    • Stránka môže byť dočasne nedostupná alebo zaneprázdnená. Svoj pokus opakujte neskôr.
    • +
    • Ak sa nedá načítať žiadna stránka, skontrolujte pripojenie svojho zariadenia k internetu.
    • +
    + ]]>
    + Nebezpečný typ obsahu @@ -104,33 +136,144 @@ Poškodený obsah stránky + + Táto stránka nemohla byť zobrazená kvôli chybe pri prenose údajov.

    +
      +
    • Kontaktujte prevádzkovateľa webovej stránky a informujte ho o tomto probléme.
    • +
    + ]]>
    + Obsah zlyhal + Táto stránka nemohla byť zobrazená kvôli chybe pri prenose údajov.

    +
      +
    • Kontaktujte prevádzkovateľa webovej stránky a informujte ho o probléme.
    • +
    + ]]>
    + Chyba kódovania obsahu + Stránka nemôže byť zobrazená, pretože používa neplatné alebo nepodporované formátovanie.

    +
      +
    • Prosím, kontaktujte majiteľov stránky a informujte ich o tomto probléme.
    • +
    + ]]>
    + Adresa sa nenašla + + URL adresa nezodpovedá žiadnemu serveru a nie je možné ju načítať.

    +
      +
    • Skontrolujte, či ste adresu napísali správne (napr. že neobsahuje + ww.example.com namiesto + www.example.com).
    • +
    • Ak nemôžete načítať žiadnu stránku, skontrolujte pripojenie svojho zariadenia k internetu.
    • +
    + ]]>
    + Neplatná adresa + Adresa (URL) nie je platná a nemožno ju načítať. Prosím, skontrolujte text v paneli s adresou a skúste to znova.

    + ]]>
    Adresa nie je platná + + +
  • Webové adresy sú zvyčajne zadávané v tvare http://www.example.com/
  • +
  • Skontrolujte, či používate správne lomky (t.j. /).
  • + + ]]>
    + Neznámy protokol + Adresa sa začína protokolom, ktorý prehliadač nepozná. Protokol je reťazec na začiatku adresy, ako napríklad https: alebo ftp:, ktorý hovorí prehliadaču, ako sa má pripojiť ku serveru..

    +
      +
    • Chcete sa pripojiť k multimédiám alebo iným netextovým službám?
    • +
    • Niektoré protokoly vyžadujú softvér tretích strán alebo doplnky.
    • +
    + ]]>
    + Súbor nebol nájdený + +
  • Je možné, že bol odstránený, premenovaný alebo premiestnený?
  • +
  • Skontrolujte, či má adresa správny formát a či neobsahuje chyby.
  • +
  • Máte príslušné povolenia na zobrazenie daného súboru?
  • + + ]]>
    + Prístup k súboru bol zamietnutý + +
  • Mohol byť odstránený, premiestnený alebo vám v prístupe bránia oprávnenia.
  • + + ]]>
    + Proxy server odmietol spojenie + Prehliadač je nakonfigurovaný na používanie proxy servera, no tento odmietol pripojenie.

    +
      +
    • Skontrolujte nastavenia proxy servera v prehliadači a skúste to znova.
    • +
    • Má služba proxy povolený prístup k sieti?
    • +
    • Ak problémy pretrvávajú, kontaktujte, prosím, svojho správcu siete alebo poskytovateľa internetu.
    • +
    + ]]>
    + Proxy server nenájdený - + Prehliadač je nakonfigurovaný na používanie proxy servera, no tento odmietol pripojenie.

    +
      +
    • Skontrolujte nastavenia proxy servera v prehliadači a skúste to znova.
    • +
    • Je zariadenie pripojené k aktívnej sieti?
    • +
    • Ak problémy pretrvávajú, kontaktujte, prosím, svojho správcu siete alebo poskytovateľa internetu.
    • +
    + ]]>
    + + + Stránka so škodlivým softvérom + + Stránka %1$s bola označená ako nebezpečná a na základe nastavení zabezpečenia bola zablokovaná.

    + ]]>
    + + + Nežiadúca webová stránka + + Stránka %1$s bola označená ako ponúkajúca nevyžiadaný softvér a na základe nastavení zabezpečenia bola zablokovaná.

    + ]]>
    + + + Škodlivá stránka + + Stránka %1$s bola označená ako nebezpečná a na základe nastavení zabezpečenia bola zablokovaná.

    + ]]>
    + + + Podvodná stránka + + Stránka %1$s bola označená ako podvodná a na základe nastavení zabezpečenia bola zablokovaná.

    + ]]>
    + diff --git a/components/browser/toolbar/src/main/res/values-cs/strings.xml b/components/browser/toolbar/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..ad66590b73f --- /dev/null +++ b/components/browser/toolbar/src/main/res/values-cs/strings.xml @@ -0,0 +1,8 @@ + + + + Nabídka + Vymazat + + Načítání + diff --git a/components/browser/toolbar/src/main/res/values-es-rAR/strings.xml b/components/browser/toolbar/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..53795888a22 --- /dev/null +++ b/components/browser/toolbar/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,8 @@ + + + + Menú + Eliminar + + Cargando + diff --git a/components/browser/toolbar/src/main/res/values-fi/strings.xml b/components/browser/toolbar/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..fdfa0108cc3 --- /dev/null +++ b/components/browser/toolbar/src/main/res/values-fi/strings.xml @@ -0,0 +1,8 @@ + + + + Valikko + Tyhjennä + + Ladataan + diff --git a/components/browser/toolbar/src/main/res/values-pa-rIN/strings.xml b/components/browser/toolbar/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..561ab297106 --- /dev/null +++ b/components/browser/toolbar/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,8 @@ + + + + ਮੇਨੂ + ਸਾਫ਼ ਕਰੋ + + ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ + diff --git a/components/feature/app-links/src/main/res/values-cs/strings.xml b/components/feature/app-links/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..3b4af4acb55 --- /dev/null +++ b/components/feature/app-links/src/main/res/values-cs/strings.xml @@ -0,0 +1,11 @@ + + + + Otevřít v… + + Chcete odkaz otevřít v jiné aplikaci? Vaše prohlížení nemusí zůstat anonymní. + + Otevřít + + Zrušit + diff --git a/components/feature/app-links/src/main/res/values-es-rAR/strings.xml b/components/feature/app-links/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..02c2d96dff9 --- /dev/null +++ b/components/feature/app-links/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,11 @@ + + + + Abrir en… + + ¿Abrir en aplicación? Es posible que tu actividad deje de ser privada. + + Abrir + + Cancelar + diff --git a/components/feature/app-links/src/main/res/values-eu/strings.xml b/components/feature/app-links/src/main/res/values-eu/strings.xml index 9b4f0aaad6e..e3a1e6e827e 100644 --- a/components/feature/app-links/src/main/res/values-eu/strings.xml +++ b/components/feature/app-links/src/main/res/values-eu/strings.xml @@ -2,6 +2,10 @@ Ireki honekin… + + Aplikazioan ireki? Baliteke zure jarduera pribatua ez izatea hemendik aurrera. Ireki - + + Utzi + diff --git a/components/feature/app-links/src/main/res/values-fi/strings.xml b/components/feature/app-links/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..9c295ff31be --- /dev/null +++ b/components/feature/app-links/src/main/res/values-fi/strings.xml @@ -0,0 +1,11 @@ + + + + Avaa sovelluksella… + + Avaa sovelluksella? Toimesi eivät välttämättä ole enää yksityisiä. + + Avaa + + Peruuta + diff --git a/components/feature/app-links/src/main/res/values-pa-rIN/strings.xml b/components/feature/app-links/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..ceab13ad45a --- /dev/null +++ b/components/feature/app-links/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,9 @@ + + + + …ਨਾਲ ਖੋਲ੍ਹੋ + + ਖੋਲ੍ਹੋ + + ਰੱਦ ਕਰੋ + diff --git a/components/feature/contextmenu/src/main/res/values-cs/strings.xml b/components/feature/contextmenu/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..d18e1d79618 --- /dev/null +++ b/components/feature/contextmenu/src/main/res/values-cs/strings.xml @@ -0,0 +1,25 @@ + + + + Otevřít odkaz v novém panelu + + Otevřít odkaz v anonymním panelu + + Otevřít obrázek v novém panelu + + Sdílet odkaz + + Kopírovat odkaz + + Kopírovat adresu obrázku + + Uložit obrázek + + Nový panel otevřen + + Nový anonymní panel otevřen + + Text zkopírován do schránky + + Přepnout + diff --git a/components/feature/contextmenu/src/main/res/values-es-rAR/strings.xml b/components/feature/contextmenu/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..59c775a001b --- /dev/null +++ b/components/feature/contextmenu/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,25 @@ + + + + Abrir enlace en una pestaña nueva + + Abrir enlace en una pestaña privada + + Abrir la imagen en una pestaña nueva + + Compartir enlace + + Copiar enlace + + Copiar ubicación de la imagen + + Guardar imagen + + Se abrió una pestaña nueva + + Se abrió una nueva pestaña privada + + Texto copiado al portapapeles + + Intercambiar + diff --git a/components/feature/contextmenu/src/main/res/values-eu/strings.xml b/components/feature/contextmenu/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..ff2fba65e77 --- /dev/null +++ b/components/feature/contextmenu/src/main/res/values-eu/strings.xml @@ -0,0 +1,25 @@ + + + + Ireki lotura fitxa berrian + + Ireki lotura fitxa pribatuan + + Ireki irudia fitxa berrian + + Partekatu lotura + + Kopiatu lotura + + Kopiatu irudiaren helbidea + + Gorde irudia + + Fitxa berria ireki da + + Fitxa pribatu berria ireki da + + Testua arbelera kopiatu da + + Aldatu + diff --git a/components/feature/contextmenu/src/main/res/values-fi/strings.xml b/components/feature/contextmenu/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..b8f896399eb --- /dev/null +++ b/components/feature/contextmenu/src/main/res/values-fi/strings.xml @@ -0,0 +1,25 @@ + + + + Avaa linkki uuteen välilehteen + + Avaa linkki uuteen yksityiseen välilehteen + + Avaa kuva uuteen välilehteen + + Jaa linkki + + Kopioi linkki + + Kopioi kuvan sijainti + + Tallenna kuva + + Uusi välilehti avattu + + Uusi yksityinen välilehti avattu + + Teksti kopioitu leikepöydälle + + Vaihda + diff --git a/components/feature/contextmenu/src/main/res/values-pa-rIN/strings.xml b/components/feature/contextmenu/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..36f969e06bd --- /dev/null +++ b/components/feature/contextmenu/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,25 @@ + + + + ਨਵੀਂ ਟੈਬ ‘ਚ ਲਿੰਕ ਖੋਲ੍ਹੋ + + ਲਿੰਕ ਪ੍ਰਾਈਵੇਟ ਟੈਬ ‘ਚ ਖੋਲ੍ਹੋ + + ਚਿੱਤਰ ਨਵੀਂ ਟੈਬ ‘ਚ ਖੋਲ੍ਹੋ + + ਲਿੰਕ ਸਾਂਝਾ ਕਰੋ + + ਲਿੰਕ ਕਾਪੀ ਕਰੋ + + ਚਿੱਤਰ ਟਿਕਾਣਾ ਕਾਪੀ ਕਰੋ + + ਚਿੱਤਰ ਸੰਭਾਲੋ + + ਨਵੀਂ ਟੈਬ ਖੋਲ੍ਹੀ + + ਨਵੀਂ ਪ੍ਰਾਈਵੈਟ ਟੈਬ ਖੋਲ੍ਹੀ + + ਲਿਖਤ ਨੂੰ ਕਲਿੱਪਬੋਰਡ ‘ਚ ਨਕਲ ਕੀਤਾ + + ਬਦਲੋ + diff --git a/components/feature/customtabs/src/main/res/values-cs/strings.xml b/components/feature/customtabs/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..0a6027a0ec3 --- /dev/null +++ b/components/feature/customtabs/src/main/res/values-cs/strings.xml @@ -0,0 +1,5 @@ + + + Návrat do předchozí aplikace + Sdílet odkaz + diff --git a/components/feature/customtabs/src/main/res/values-es-rAR/strings.xml b/components/feature/customtabs/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..ec4b3f66e2d --- /dev/null +++ b/components/feature/customtabs/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,5 @@ + + + Volver a la aplicación anterior + Compartir enlace + diff --git a/components/feature/customtabs/src/main/res/values-eu/strings.xml b/components/feature/customtabs/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..0494ad16ad9 --- /dev/null +++ b/components/feature/customtabs/src/main/res/values-eu/strings.xml @@ -0,0 +1,5 @@ + + + Itzuli aurreko aplikaziora + Partekatu lotura + diff --git a/components/feature/customtabs/src/main/res/values-fi/strings.xml b/components/feature/customtabs/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..9eb780ce768 --- /dev/null +++ b/components/feature/customtabs/src/main/res/values-fi/strings.xml @@ -0,0 +1,5 @@ + + + Palaa edelliseen sovellukseen + Jaa linkki + diff --git a/components/feature/customtabs/src/main/res/values-pa-rIN/strings.xml b/components/feature/customtabs/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..9a2a887cabf --- /dev/null +++ b/components/feature/customtabs/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,5 @@ + + + ਪਿਛਲੀ ਐਪ ‘ਤੇ ਜਾਓ + ਲਿੰਕ ਸਾਂਝਾ ਕਰੋ + diff --git a/components/feature/downloads/src/main/res/values-cs/strings.xml b/components/feature/downloads/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..714cc1b9207 --- /dev/null +++ b/components/feature/downloads/src/main/res/values-cs/strings.xml @@ -0,0 +1,19 @@ + + + + Stahování + + Stahování + + + Probíhá stahování + + + Stáhnout soubor + + Stáhnout + + Zrušit + + %1$s nemůže stáhnout tento typ souboru + diff --git a/components/feature/downloads/src/main/res/values-es-rAR/strings.xml b/components/feature/downloads/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..191c089b044 --- /dev/null +++ b/components/feature/downloads/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,18 @@ + + + + Descargas + + Descargando + + Descarga en proceso + + + Descargar archivo + + Descargar + + Cancelar + + %1$s no puede descargar este tipo de archivo + diff --git a/components/feature/downloads/src/main/res/values-eu/strings.xml b/components/feature/downloads/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..7aa4ea0c635 --- /dev/null +++ b/components/feature/downloads/src/main/res/values-eu/strings.xml @@ -0,0 +1,18 @@ + + + + Deskargak + + Deskargatzen + + Deskargatzen ari da + + + Deskargatu fitxategia + + Deskargatu + + Utzi + + %1$s(e)k ezin du fitxategi mota hau deskargatu + diff --git a/components/feature/downloads/src/main/res/values-fi/strings.xml b/components/feature/downloads/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..eb670402cf8 --- /dev/null +++ b/components/feature/downloads/src/main/res/values-fi/strings.xml @@ -0,0 +1,18 @@ + + + + Lataukset + + Ladataan + + Lataus meneillään + + + Lataa tiedosto + + Lataa + + Peruuta + + %1$s ei voi ladata tätä tiedostotyyppiä + diff --git a/components/feature/downloads/src/main/res/values-pa-rIN/strings.xml b/components/feature/downloads/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..04b652a66bd --- /dev/null +++ b/components/feature/downloads/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,18 @@ + + + + ਡਾਊਨਲੋਡ + + ਡਾਊਨਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ + + ਡਾਊਨਲੋਡ ਜਾਰੀ ਹੈ + + + ਫਾਈਲ ਡਾਊਨਲੋਡ + + ਡਾਊਨਲੋਡ ਕਰੋ + + ਰੱਦ ਕਰੋ + + %1$s ਇਹ ਫਾਈਲ ਕਿਸਮ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕਰ ਸਕਦਾ ਹੈ + diff --git a/components/feature/findinpage/src/main/res/values-cs/strings.xml b/components/feature/findinpage/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..f03ea222502 --- /dev/null +++ b/components/feature/findinpage/src/main/res/values-cs/strings.xml @@ -0,0 +1,24 @@ + + + + + Najít na stránce + + + %1$d/%2$d + + + %1$d z %2$d + + + Najít další + + + Najít předchozí + + + Ukončit hledání na stránce + + diff --git a/components/feature/findinpage/src/main/res/values-es-rAR/strings.xml b/components/feature/findinpage/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..77b5b926a64 --- /dev/null +++ b/components/feature/findinpage/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,24 @@ + + + + + Buscar en la página + + + %1$d/%2$d + + + %1$d de %2$d + + + Buscar resultado siguiente + + + Buscar resultado anterior + + + Descartar la búsqueda en la página + + diff --git a/components/feature/findinpage/src/main/res/values-eu/strings.xml b/components/feature/findinpage/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..99aa6f857ac --- /dev/null +++ b/components/feature/findinpage/src/main/res/values-eu/strings.xml @@ -0,0 +1,24 @@ + + + + + Bilatu orrian + + + %2$d/%1$d + + + %2$d(e)tik %1$d + + + Bilatu hurrengo emaitza + + + Bilatu aurreko emaitza + + + Baztertu orrian bilatzea + + diff --git a/components/feature/findinpage/src/main/res/values-fi/strings.xml b/components/feature/findinpage/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..872cfd6b87b --- /dev/null +++ b/components/feature/findinpage/src/main/res/values-fi/strings.xml @@ -0,0 +1,17 @@ + + + + + Etsi sivulta + + + %1$d/%2$d + + + Etsi seuraava osuma + + + Etsi edellinen osuma + + diff --git a/components/feature/findinpage/src/main/res/values-pa-rIN/strings.xml b/components/feature/findinpage/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..f7483188f6b --- /dev/null +++ b/components/feature/findinpage/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + + ਸਫ਼ੇ ‘ਚ ਲੱਭੋ + + + %1$d/%2$d + + + %2$d ‘ਚੋਂ %1$d + + + ਅਗਲਾ ਨਤੀਜਾ ਲੱਭੋ + + + ਪਿਛਲਾ ਨਤੀਜਾ ਲੱਭੋ + + diff --git a/components/feature/media/src/main/res/values-cs/strings.xml b/components/feature/media/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..3d03ef09b5e --- /dev/null +++ b/components/feature/media/src/main/res/values-cs/strings.xml @@ -0,0 +1,12 @@ + + + + Média + + + Kamera je zapnuta + + Mikrofon je zapnut + + Kamera a mikrofon jsou zapnuty + diff --git a/components/feature/media/src/main/res/values-es-rAR/strings.xml b/components/feature/media/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..44bb2668c0d --- /dev/null +++ b/components/feature/media/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,12 @@ + + + + Medios + + + La cámara está encendida + + El micrófono está encendido + + La cámara y el micrófono están encendidos + diff --git a/components/feature/media/src/main/res/values-eu/strings.xml b/components/feature/media/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..16c663713a8 --- /dev/null +++ b/components/feature/media/src/main/res/values-eu/strings.xml @@ -0,0 +1,12 @@ + + + + Media + + + Kamera piztuta dago + + Mikrofonoa piztuta dago + + Kamera eta mikrofonoa piztuta daude + diff --git a/components/feature/media/src/main/res/values-fi/strings.xml b/components/feature/media/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..4c20dcc05e3 --- /dev/null +++ b/components/feature/media/src/main/res/values-fi/strings.xml @@ -0,0 +1,12 @@ + + + + Media + + + Kamera on päällä + + Mikrofoni on päällä + + Kamera ja mikrofoni ovat päällä + diff --git a/components/feature/media/src/main/res/values-pa-rIN/strings.xml b/components/feature/media/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..b3eaa295d36 --- /dev/null +++ b/components/feature/media/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,13 @@ + + + + + ਮੀਡਿਆ + + + ਕੈਮਰਾ ਚਾਲੂ ਹੈ + + ਮਾਈਕਰੋਫੋਨ ਚਾਲੂ ਹੈ + + ਕੈਮਰਾ ਤੇ ਮਾਈਕਰੋਫ਼ੋਨ ਚਾਲ ਹਨ + diff --git a/components/feature/prompts/src/main/res/values-cs/strings.xml b/components/feature/prompts/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..2f0a941c1c7 --- /dev/null +++ b/components/feature/prompts/src/main/res/values-cs/strings.xml @@ -0,0 +1,28 @@ + + + + OK + + Zrušit + + Zabránit stránce ve vytváření dalších dialogů + + Nastavit + + Vymazat + + Přihlášení + + Uživatelské jméno + + Heslo + + + Štítek vstupního pole pro zadání textu + + Vyberte barvu + + Povolit + + Zakázat + diff --git a/components/feature/prompts/src/main/res/values-es-rAR/strings.xml b/components/feature/prompts/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..29ace017748 --- /dev/null +++ b/components/feature/prompts/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,28 @@ + + + + Aceptar + + Cancelar + + Impedir que esta página cree diálogos adicionales + + Establecer + + Eliminar + + Iniciar sesión + + Nombre de usuario + + Contraseña + + + Etiqueta para ingresar un campo de entrada de texto + + Elija un color + + Permitir + + Denegar + diff --git a/components/feature/prompts/src/main/res/values-eu/strings.xml b/components/feature/prompts/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..e5f9f16368b --- /dev/null +++ b/components/feature/prompts/src/main/res/values-eu/strings.xml @@ -0,0 +1,28 @@ + + + + Ados + + Utzi + + Eragotzi orri honi elkarrizketa-koadro gehiago sortzea + + Ezarri + + Garbitu + + Hasi saioa + + Erabiltzaile-izena + + Pasahitza + + + Testua idazteko eremua sartzeko etiketa + + Aukeratu kolore bat + + Baimendu + + Ukatu + diff --git a/components/feature/prompts/src/main/res/values-fi/strings.xml b/components/feature/prompts/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..5e5e8f42467 --- /dev/null +++ b/components/feature/prompts/src/main/res/values-fi/strings.xml @@ -0,0 +1,21 @@ + + + + OK + + Peruuta + + Estä tätä sivua luomasta lisäikkunoita + + Kirjaudu sisään + + Käyttäjätunnus + + Salasana + + Valitse väri + + Salli + + Estä + diff --git a/components/feature/prompts/src/main/res/values-pa-rIN/strings.xml b/components/feature/prompts/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..f9e159772b6 --- /dev/null +++ b/components/feature/prompts/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,28 @@ + + + + ਠੀਕ ਹੈ + + ਰੱਦ ਕਰੋ + + ਇਸ ਸਫ਼ੇ ਨੂੰ ਹੋਰ ਡਾਈਲਾਗ ਬਣਾਉਣ ਤੋਂ ਰੋਕੋ + + ਨਿਯਤ ਕਰੋ + + ਸਾਫ਼ ਕਰੋ + + ਸਾਈਨ ਇਨ + + ਵਰਤੋਂਕਾਰ ਨਾਂ + + ਪਾਸਵਰਡ + + + ਲਿਖਤ ਦਰਜ ਕਰਨ ਲਈ ਖੇਤਰ ਲਈ ਲੇਬਲ + + ਰੰਗ ਚੁਣੋ + + ਆਗਿਆ ਦਿਓ + + ਇਨਕਾਰ ਕਰੋ + diff --git a/components/feature/readerview/src/main/res/values-cs/strings.xml b/components/feature/readerview/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..473300dc971 --- /dev/null +++ b/components/feature/readerview/src/main/res/values-cs/strings.xml @@ -0,0 +1,29 @@ + + + + Bezpatkové + + Bezpatkové písmo + + Patkové + + Patkové písmo + + + Zmenšení velikost písma + + + Zvětšení velikost písma + + Tmavé + + Tmavé barvy + + Sépie + + Sépiové barvy + + Světlé + + Světlé barvy + diff --git a/components/feature/readerview/src/main/res/values-es-rAR/strings.xml b/components/feature/readerview/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..e37f09be5fc --- /dev/null +++ b/components/feature/readerview/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,29 @@ + + + + Sans-serif + + Fuente Sans Serif + + Serif + + Fuente Serif + + + Disminución del tamaño de la fuente + + + Aumento del tamaño de la fuente + + Oscuro + + Esquema de color oscuro + + Sepia + + Esquema de color sepia + + Claro + + Esquema de color claro + diff --git a/components/feature/readerview/src/main/res/values-eu/strings.xml b/components/feature/readerview/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000000..df496fd857e --- /dev/null +++ b/components/feature/readerview/src/main/res/values-eu/strings.xml @@ -0,0 +1,29 @@ + + + + Sans serif + + Sans Serif letra-tipoa + + Serif + + Serif letra-tipoa + + + Txikiagotu letra tamaina + + + Handiagotu letra tamaina + + Iluna + + Kolore-eskema iluna + + Sepia + + Sepia kolore-eskema + + Argia + + Kolore-eskema argia + diff --git a/components/feature/readerview/src/main/res/values-fi/strings.xml b/components/feature/readerview/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..bfca791af6d --- /dev/null +++ b/components/feature/readerview/src/main/res/values-fi/strings.xml @@ -0,0 +1,16 @@ + + + + + Tumma + + Tumma väriteema + + Seepia + + Seepiamainen väriteema + + Vaalea + + Vaalea väriteema + diff --git a/components/feature/readerview/src/main/res/values-pa-rIN/strings.xml b/components/feature/readerview/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..69275e8e21a --- /dev/null +++ b/components/feature/readerview/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,19 @@ + + + + + ਸਨਜ ਸੈਰੀਫ਼ + + ਸਨਜ ਸੈਰੀਫ਼ ਫ਼ੋਂਟ + + ਸੈਰੀਫ਼ + + ਸੈਰੀਫ਼ ਫ਼ੋਂਟ + + + ਗੂੜ੍ਹਾ + + ਹਲਕਾ + + ਹਲਕੀ ਰੰਗ ਸਕੀਮ + diff --git a/components/feature/sitepermissions/src/main/res/values-cs/strings.xml b/components/feature/sitepermissions/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..0067af4668c --- /dev/null +++ b/components/feature/sitepermissions/src/main/res/values-cs/strings.xml @@ -0,0 +1,34 @@ + + + + Chcete serveru %1$s povolit zasílat vám oznámení? + + Chcete serveru %1$s povolit používat vaši kameru? + + Chcete serveru %1$s povolit používat váš mikrofon? + + Chcete serveru %1$s povolit přístup k vaší poloze? + + Chcete serveru %1$s povolit používat vaši kameru a mikrofon? + + Mikrofon 1 + + Zadní kamera + + Přední kamera + + Povolit + + Nepovolit + + Pamatovat si pro tento server + + Vždy + + Nikdy + diff --git a/components/feature/sitepermissions/src/main/res/values-es-rAR/strings.xml b/components/feature/sitepermissions/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..dd8a1b72441 --- /dev/null +++ b/components/feature/sitepermissions/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,34 @@ + + + + ¿Permitir que %1$s envíe notificaciones? + + ¿Permitir que %1$s use la cámara? + + ¿Permitir que %1$s use el micrófono? + + ¿Permitir que %1$s use tu ubicación? + + ¿Permitir que %1$s use la cámara y el micrófono? + + Micrófono 1 + + Cámara trasera + + Cámara frontal + + Permitir + + No permitir + + Recordar para este sitio + + Siempre + + Nunca + diff --git a/components/feature/sitepermissions/src/main/res/values-eu/strings.xml b/components/feature/sitepermissions/src/main/res/values-eu/strings.xml index 37c90f9dfc0..2723eb8d6e0 100644 --- a/components/feature/sitepermissions/src/main/res/values-eu/strings.xml +++ b/components/feature/sitepermissions/src/main/res/values-eu/strings.xml @@ -1,5 +1,32 @@ + + Baimendu %1$s(r)i jakinarazpenak bidaltzea? + + Baimendu %1$s(r)i zure kamera erabiltzea? + + Baimendu %1$s(r)i zure mikrofonoa erabiltzea? + + Baimendu %1$s(r)i zure kokapena erabiltzea? + + Baimendu %1$s(r)i zure kamera eta mikrofonoa erabiltzea? + + 1 Mikrofonoa + + Atzealdeko kamera + + Aurreko kamera + + Baimendu + + Ez baimendu + + Gogoratu erabakia gune honetarako Beti diff --git a/components/feature/sitepermissions/src/main/res/values-fi/strings.xml b/components/feature/sitepermissions/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..a2cebbb6e03 --- /dev/null +++ b/components/feature/sitepermissions/src/main/res/values-fi/strings.xml @@ -0,0 +1,24 @@ + + + + Mikrofoni 1 + + Takakamera + + Etukamera + + Salli + + Älä salli + + Muista valinta tälle sivustolle + + Aina + + Ei koskaan + diff --git a/components/feature/sitepermissions/src/main/res/values-pa-rIN/strings.xml b/components/feature/sitepermissions/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..b9c1110ed68 --- /dev/null +++ b/components/feature/sitepermissions/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,34 @@ + + + + %1$s ਨੂੰ ਸੂਚਨਾਵਾਂ ਦੇਣ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ? + + %1$s ਨੂੰ ਆਪਣਾ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ? + + %1$s ਨੂੰ ਆਪਣਾ ਮਾਈਕਰੋਫ਼ੋਨ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ? + + %1$s ਨੂੰ ਆਪਣਾ ਟਿਕਾਣਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ? + + %1$s ਨੂੰ ਆਪਣਾ ਕੈਮਰਾ ਅਤੇ ਮਾਈਕਰੋਫ਼ੋਨ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ? + + ਮਾਈਕਰੋਫ਼ੋਨ 1 + + ਪਿਛਲੇ ਪਾਸੇ ਵਾਲਾ ਕੈਮਰਾ + + ਅੱਗੇ ਪਾਸੇ ਵਾਲਾ ਕੈਮਰਾ + + ਆਗਿਆ ਦਿਓ + + ਆਗਿਆ ਨਾ ਦਿਓ + + ਇਸ ਸਾਈਟ ਲਈ ਫ਼ੈਸਲਾ ਯਾਦ ਰੱਖੋ + + ਹਮੇਸ਼ਾਂ + + ਕਦੇ ਨਹੀਂ + diff --git a/components/feature/tabs/src/main/res/values-cs/strings.xml b/components/feature/tabs/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..1e585bd5677 --- /dev/null +++ b/components/feature/tabs/src/main/res/values-cs/strings.xml @@ -0,0 +1,5 @@ + + + + Panely + diff --git a/components/feature/tabs/src/main/res/values-es-rAR/strings.xml b/components/feature/tabs/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..e1481954ae2 --- /dev/null +++ b/components/feature/tabs/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,5 @@ + + + + Pestañas + diff --git a/components/feature/tabs/src/main/res/values-fi/strings.xml b/components/feature/tabs/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..43d0a4b9ee6 --- /dev/null +++ b/components/feature/tabs/src/main/res/values-fi/strings.xml @@ -0,0 +1,5 @@ + + + + Välilehdet + diff --git a/components/feature/tabs/src/main/res/values-pa-rIN/strings.xml b/components/feature/tabs/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..b4afae05513 --- /dev/null +++ b/components/feature/tabs/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,5 @@ + + + + ਟੈਬਾਂ + diff --git a/components/lib/crash/src/main/res/values-cs/strings.xml b/components/lib/crash/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..4e49f6acb89 --- /dev/null +++ b/components/lib/crash/src/main/res/values-cs/strings.xml @@ -0,0 +1,21 @@ + + + + Promiňte. V aplikaci %1$s nastal problém a spadla. + + + Poslat hlášení o pádu společnosti %1$s + + + Zavřít + + + Restartovat aplikaci %s + + + Pády + + + Nahlásit + + diff --git a/components/lib/crash/src/main/res/values-es-rAR/strings.xml b/components/lib/crash/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..98cece0127b --- /dev/null +++ b/components/lib/crash/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,21 @@ + + + + Disculpá. %1$s tuvo un problema y falló. + + + Enviar informe del fallo a %1$s + + + Cerrar + + + Reiniciar %1$s + + + Fallos + + + Informar + + diff --git a/components/lib/crash/src/main/res/values-fi/strings.xml b/components/lib/crash/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..e81b6248d7a --- /dev/null +++ b/components/lib/crash/src/main/res/values-fi/strings.xml @@ -0,0 +1,19 @@ + + + + + Lähetä kaatumisraportti %1$slle + + + Sulje + + + Käynnistä %1$s uudelleen + + + Kaatumiset + + + Lähetä raportti + + diff --git a/components/lib/crash/src/main/res/values-in/strings.xml b/components/lib/crash/src/main/res/values-in/strings.xml index 241b414b0de..366ea560820 100644 --- a/components/lib/crash/src/main/res/values-in/strings.xml +++ b/components/lib/crash/src/main/res/values-in/strings.xml @@ -10,6 +10,12 @@ Tutup + + Mulai Ulang %1$s + + + Mogok + Laporkan diff --git a/components/lib/crash/src/main/res/values-pa-rIN/strings.xml b/components/lib/crash/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..808c17c9d30 --- /dev/null +++ b/components/lib/crash/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,22 @@ + + + + + ਅਫ਼ਸੋਸ ਹੈ। %1$s ਨੂੰ ਸਮੱਸਿਆ ਆਈ ਤੇ ਕਰੈਸ਼ ਹੋ ਗਿਆ ਹੈ। + + + ਕਰੈਸ਼ ਰਿਪੋਰਟ %1$s ਨੂੰ ਭੇਜੋ + + + ਬੰਦ ਕਰੋ + + + %1$s ਮੁੜ-ਚਾਲੂ ਕਰੋ + + + ਕਰੈਸ਼ + + + ਰਿਪੋਰਟ + + diff --git a/components/support/ktx/src/main/res/values-cs/strings.xml b/components/support/ktx/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000000..65840d822ca --- /dev/null +++ b/components/support/ktx/src/main/res/values-cs/strings.xml @@ -0,0 +1,5 @@ + + + Sdílet pomocí… + Sdílet pomocí + diff --git a/components/support/ktx/src/main/res/values-es-rAR/strings.xml b/components/support/ktx/src/main/res/values-es-rAR/strings.xml new file mode 100644 index 00000000000..0ff0ff169b2 --- /dev/null +++ b/components/support/ktx/src/main/res/values-es-rAR/strings.xml @@ -0,0 +1,5 @@ + + + Compartir con… + Compartir vía + diff --git a/components/support/ktx/src/main/res/values-fi/strings.xml b/components/support/ktx/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000000..df6f127604c --- /dev/null +++ b/components/support/ktx/src/main/res/values-fi/strings.xml @@ -0,0 +1,5 @@ + + + Jaa… + Jaa + diff --git a/components/support/ktx/src/main/res/values-pa-rIN/strings.xml b/components/support/ktx/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 00000000000..fe441b18187 --- /dev/null +++ b/components/support/ktx/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,5 @@ + + + …ਨਾਲ ਸਾਂਝਾ ਕਰੋ + ਇਸ ਰਾਹੀਂ ਸਾਂਝਾ ਕਰੋ + From 491b19d4660f7697597fbd9714a22543d96f950d Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Mon, 12 Aug 2019 13:51:54 +0000 Subject: [PATCH 18/38] Update docs (20190812-135153) --- .../-n-o_-s-e-l-e-c-t-i-o-n.md | 2 +- .../-legacy-session-manager/add.md | 4 ++-- .../-legacy-session-manager/all.md | 2 +- .../create-session-snapshot.md | 2 +- .../create-snapshot.md | 2 +- .../find-session-by-id.md | 2 +- .../get-engine-session.md | 2 +- .../get-or-create-engine-session.md | 2 +- .../-legacy-session-manager/link.md | 2 +- .../-legacy-session-manager/on-low-memory.md | 2 +- .../-legacy-session-manager/remove-all.md | 2 +- .../remove-sessions.md | 2 +- .../-legacy-session-manager/remove.md | 2 +- .../-legacy-session-manager/restore.md | 2 +- .../-legacy-session-manager/select.md | 2 +- .../selected-session-or-throw.md | 2 +- .../selected-session.md | 2 +- .../-legacy-session-manager/sessions.md | 2 +- .../-legacy-session-manager/size.md | 2 +- .../-media/-controller/index.md | 2 +- .../-media/-controller/pause.md | 2 +- .../-media/-controller/play.md | 2 +- .../-media/-controller/seek.md | 2 +- .../-media/-controller/set-muted.md | 2 +- .../-media/-metadata/-init-.md | 8 ++++++++ .../-media/-metadata/duration.md | 11 +++++++++++ .../-media/-metadata/index.md | 19 +++++++++++++++++++ .../-media/-observer/index.md | 3 ++- .../-media/-observer/on-metadata-changed.md | 5 +++++ .../-observer/on-playback-state-changed.md | 2 +- .../-media/-playback-state/-a-b-o-r-t.md | 2 +- .../-media/-playback-state/-e-m-p-t-i-e-d.md | 2 +- .../-media/-playback-state/-e-n-d-e-d.md | 2 +- .../-media/-playback-state/-p-a-u-s-e.md | 2 +- .../-media/-playback-state/-p-l-a-y-i-n-g.md | 2 +- .../-media/-playback-state/-p-l-a-y.md | 2 +- .../-media/-playback-state/-s-e-e-k-e-d.md | 2 +- .../-media/-playback-state/-s-e-e-k-i-n-g.md | 2 +- .../-media/-playback-state/-s-t-a-l-l-e-d.md | 2 +- .../-playback-state/-s-u-s-p-e-n-d-e-d.md | 2 +- .../-media/-playback-state/-u-n-k-n-o-w-n.md | 2 +- .../-media/-playback-state/-w-a-i-t-i-n-g.md | 2 +- .../-media/-playback-state/index.md | 2 +- .../-media/index.md | 2 ++ .../-media/metadata.md | 8 ++++++++ .../-media/to-string.md | 2 +- .../-media-feature/enable.md | 2 +- .../-media-feature/index.md | 2 +- 48 files changed, 97 insertions(+), 43 deletions(-) create mode 100644 docs/api/mozilla.components.concept.engine.media/-media/-metadata/-init-.md create mode 100644 docs/api/mozilla.components.concept.engine.media/-media/-metadata/duration.md create mode 100644 docs/api/mozilla.components.concept.engine.media/-media/-metadata/index.md create mode 100644 docs/api/mozilla.components.concept.engine.media/-media/-observer/on-metadata-changed.md create mode 100644 docs/api/mozilla.components.concept.engine.media/-media/metadata.md diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/-n-o_-s-e-l-e-c-t-i-o-n.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/-n-o_-s-e-l-e-c-t-i-o-n.md index 51e75c7c061..a9edb4f5936 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/-n-o_-s-e-l-e-c-t-i-o-n.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/-n-o_-s-e-l-e-c-t-i-o-n.md @@ -2,4 +2,4 @@ # NO_SELECTION -`const val NO_SELECTION: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L542) \ No newline at end of file +`const val NO_SELECTION: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L546) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/add.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/add.md index 30ba3a593f0..8b183834112 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/add.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/add.md @@ -2,11 +2,11 @@ # add -`fun add(session: `[`Session`](../-session/index.md)`, selected: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false, engineSession: `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md)`? = null, parent: `[`Session`](../-session/index.md)`? = null): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L134) +`fun add(session: `[`Session`](../-session/index.md)`, selected: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false, engineSession: `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md)`? = null, parent: `[`Session`](../-session/index.md)`? = null): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L136) Adds the provided session. -`fun add(sessions: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Session`](../-session/index.md)`>): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L207) +`fun add(sessions: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Session`](../-session/index.md)`>): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L209) Adds multiple sessions. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/all.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/all.md index e7dc7d905fa..e49cb15e6c3 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/all.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/all.md @@ -2,7 +2,7 @@ # all -`val all: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Session`](../-session/index.md)`>` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L128) +`val all: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Session`](../-session/index.md)`>` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L130) Returns a list of all active sessions (including CustomTab sessions). diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-session-snapshot.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-session-snapshot.md index 063c8dacc1b..66ea468d1f4 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-session-snapshot.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-session-snapshot.md @@ -2,4 +2,4 @@ # createSessionSnapshot -`fun createSessionSnapshot(session: `[`Session`](../-session/index.md)`): `[`Item`](../-session-manager/-snapshot/-item/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L82) \ No newline at end of file +`fun createSessionSnapshot(session: `[`Session`](../-session/index.md)`): `[`Item`](../-session-manager/-snapshot/-item/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L84) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-snapshot.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-snapshot.md index b3500de5fb6..8c98f88deb0 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-snapshot.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/create-snapshot.md @@ -2,7 +2,7 @@ # createSnapshot -`fun createSnapshot(): `[`Snapshot`](../-session-manager/-snapshot/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L42) +`fun createSnapshot(): `[`Snapshot`](../-session-manager/-snapshot/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L44) Produces a snapshot of this manager's state, suitable for restoring via [SessionManager.restore](../-session-manager/restore.md). Only regular sessions are included in the snapshot. Private and Custom Tab sessions are omitted. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/find-session-by-id.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/find-session-by-id.md index ccbed2c086f..b53725f56ee 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/find-session-by-id.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/find-session-by-id.md @@ -2,7 +2,7 @@ # findSessionById -`fun findSessionById(id: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Session`](../-session/index.md)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L525) +`fun findSessionById(id: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`): `[`Session`](../-session/index.md)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L527) Finds and returns the session with the given id. Returns null if no matching session could be found. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-engine-session.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-engine-session.md index ce1016c7e5f..5bd435a82c9 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-engine-session.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-engine-session.md @@ -2,7 +2,7 @@ # getEngineSession -`fun getEngineSession(session: `[`Session`](../-session/index.md)` = selectedSessionOrThrow): `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L272) +`fun getEngineSession(session: `[`Session`](../-session/index.md)` = selectedSessionOrThrow): `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L274) Gets the linked engine session for the provided session (if it exists). diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-or-create-engine-session.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-or-create-engine-session.md index f339f4324dd..f912bc5f4b2 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-or-create-engine-session.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/get-or-create-engine-session.md @@ -2,7 +2,7 @@ # getOrCreateEngineSession -`fun getOrCreateEngineSession(session: `[`Session`](../-session/index.md)` = selectedSessionOrThrow): `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L277) +`fun getOrCreateEngineSession(session: `[`Session`](../-session/index.md)` = selectedSessionOrThrow): `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L279) Gets the linked engine session for the provided session and creates it if needed. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/link.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/link.md index 18a1888271b..4a8b60a350b 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/link.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/link.md @@ -2,4 +2,4 @@ # link -`fun link(session: `[`Session`](../-session/index.md)`, engineSession: `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L290) \ No newline at end of file +`fun link(session: `[`Session`](../-session/index.md)`, engineSession: `[`EngineSession`](../../mozilla.components.concept.engine/-engine-session/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L292) \ No newline at end of file diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/on-low-memory.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/on-low-memory.md index da0a950f201..fa11b3ebd8d 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/on-low-memory.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/on-low-memory.md @@ -2,7 +2,7 @@ # onLowMemory -`fun onLowMemory(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L531) +`fun onLowMemory(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L535) Informs this [SessionManager](../-session-manager/index.md) that the OS is in low memory condition so it can reduce its allocated objects. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-all.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-all.md index 22aa9a5178f..1b117e5adbb 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-all.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-all.md @@ -2,7 +2,7 @@ # removeAll -`fun removeAll(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L495) +`fun removeAll(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L497) Removes all sessions including CustomTab sessions. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-sessions.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-sessions.md index b88e37db84a..6395367746b 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-sessions.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove-sessions.md @@ -2,7 +2,7 @@ # removeSessions -`fun removeSessions(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L479) +`fun removeSessions(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L481) Removes all sessions but CustomTab sessions. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove.md index a1659c62534..a077ef74c1d 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/remove.md @@ -2,7 +2,7 @@ # remove -`fun remove(session: `[`Session`](../-session/index.md)` = selectedSessionOrThrow, selectParentIfExists: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L317) +`fun remove(session: `[`Session`](../-session/index.md)` = selectedSessionOrThrow, selectParentIfExists: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L319) Removes the provided session. If no session is provided then the selected session is removed. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/restore.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/restore.md index 96f73508ad8..11f0dbae5bf 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/restore.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/restore.md @@ -2,7 +2,7 @@ # restore -`fun restore(snapshot: `[`Snapshot`](../-session-manager/-snapshot/index.md)`, updateSelection: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = true): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L240) +`fun restore(snapshot: `[`Snapshot`](../-session-manager/-snapshot/index.md)`, updateSelection: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = true): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L242) Restores sessions from the provided [Snapshot](#). diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/select.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/select.md index 707895d5f27..90f983d9c79 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/select.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/select.md @@ -2,7 +2,7 @@ # select -`fun select(session: `[`Session`](../-session/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L509) +`fun select(session: `[`Session`](../-session/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L511) Marks the given session as selected. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session-or-throw.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session-or-throw.md index 6ec240a5645..7489550c885 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session-or-throw.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session-or-throw.md @@ -2,7 +2,7 @@ # selectedSessionOrThrow -`val selectedSessionOrThrow: `[`Session`](../-session/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L116) +`val selectedSessionOrThrow: `[`Session`](../-session/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L118) Gets the currently selected session or throws an IllegalStateException if no session is selected. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session.md index 8354a9c809b..820927fbd05 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/selected-session.md @@ -2,7 +2,7 @@ # selectedSession -`val selectedSession: `[`Session`](../-session/index.md)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L95) +`val selectedSession: `[`Session`](../-session/index.md)`?` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L97) Gets the currently selected session if there is one. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/sessions.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/sessions.md index 2125e3ad715..34fca2deaae 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/sessions.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/sessions.md @@ -2,7 +2,7 @@ # sessions -`val sessions: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Session`](../-session/index.md)`>` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L122) +`val sessions: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Session`](../-session/index.md)`>` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L124) Returns a list of active sessions and filters out sessions used for CustomTabs. diff --git a/docs/api/mozilla.components.browser.session/-legacy-session-manager/size.md b/docs/api/mozilla.components.browser.session/-legacy-session-manager/size.md index 1b54b222875..a4c8f485087 100644 --- a/docs/api/mozilla.components.browser.session/-legacy-session-manager/size.md +++ b/docs/api/mozilla.components.browser.session/-legacy-session-manager/size.md @@ -2,7 +2,7 @@ # size -`val size: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L33) +`val size: `[`Int`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/browser/session/src/main/java/mozilla/components/browser/session/LegacySessionManager.kt#L35) Returns the number of session including CustomTab sessions. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-controller/index.md b/docs/api/mozilla.components.concept.engine.media/-media/-controller/index.md index 200a6fa9f37..2272d7ecdb6 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-controller/index.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-controller/index.md @@ -2,7 +2,7 @@ # Controller -`interface Controller` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L39) +`interface Controller` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L45) Controller for controlling playback of a media element. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-controller/pause.md b/docs/api/mozilla.components.concept.engine.media/-media/-controller/pause.md index fc7cbde09da..56412797883 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-controller/pause.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-controller/pause.md @@ -2,7 +2,7 @@ # pause -`abstract fun pause(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L43) +`abstract fun pause(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L49) Pauses the media. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-controller/play.md b/docs/api/mozilla.components.concept.engine.media/-media/-controller/play.md index f5d9e47e7f9..f4a5baa34a5 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-controller/play.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-controller/play.md @@ -2,7 +2,7 @@ # play -`abstract fun play(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L48) +`abstract fun play(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L54) Plays the media. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-controller/seek.md b/docs/api/mozilla.components.concept.engine.media/-media/-controller/seek.md index 6d64383b448..9d723850b45 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-controller/seek.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-controller/seek.md @@ -2,7 +2,7 @@ # seek -`abstract fun seek(time: `[`Double`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L53) +`abstract fun seek(time: `[`Double`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L59) Seek the media to a given time. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-controller/set-muted.md b/docs/api/mozilla.components.concept.engine.media/-media/-controller/set-muted.md index 6120b99bd2b..99240a1c420 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-controller/set-muted.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-controller/set-muted.md @@ -2,7 +2,7 @@ # setMuted -`abstract fun setMuted(muted: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L58) +`abstract fun setMuted(muted: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L64) Mutes/Unmutes the media. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-metadata/-init-.md b/docs/api/mozilla.components.concept.engine.media/-media/-metadata/-init-.md new file mode 100644 index 00000000000..6584fdd13e8 --- /dev/null +++ b/docs/api/mozilla.components.concept.engine.media/-media/-metadata/-init-.md @@ -0,0 +1,8 @@ +[android-components](../../../index.md) / [mozilla.components.concept.engine.media](../../index.md) / [Media](../index.md) / [Metadata](index.md) / [<init>](./-init-.md) + +# <init> + +`Metadata(duration: `[`Double`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)` = -1.0)` + +Metadata associated with [Media](../index.md). + diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-metadata/duration.md b/docs/api/mozilla.components.concept.engine.media/-media/-metadata/duration.md new file mode 100644 index 00000000000..b5c26548b7f --- /dev/null +++ b/docs/api/mozilla.components.concept.engine.media/-media/-metadata/duration.md @@ -0,0 +1,11 @@ +[android-components](../../../index.md) / [mozilla.components.concept.engine.media](../../index.md) / [Media](../index.md) / [Metadata](index.md) / [duration](./duration.md) + +# duration + +`val duration: `[`Double`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L144) + +Indicates the duration of the media in seconds. + +### Property + +`duration` - Indicates the duration of the media in seconds. \ No newline at end of file diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-metadata/index.md b/docs/api/mozilla.components.concept.engine.media/-media/-metadata/index.md new file mode 100644 index 00000000000..b87227d2120 --- /dev/null +++ b/docs/api/mozilla.components.concept.engine.media/-media/-metadata/index.md @@ -0,0 +1,19 @@ +[android-components](../../../index.md) / [mozilla.components.concept.engine.media](../../index.md) / [Media](../index.md) / [Metadata](./index.md) + +# Metadata + +`data class Metadata` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L143) + +Metadata associated with [Media](../index.md). + +### Constructors + +| Name | Summary | +|---|---| +| [<init>](-init-.md) | `Metadata(duration: `[`Double`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)` = -1.0)`
    Metadata associated with [Media](../index.md). | + +### Properties + +| Name | Summary | +|---|---| +| [duration](duration.md) | `val duration: `[`Double`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
    Indicates the duration of the media in seconds. | diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-observer/index.md b/docs/api/mozilla.components.concept.engine.media/-media/-observer/index.md index fcd04dfc21e..7e43b6db184 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-observer/index.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-observer/index.md @@ -2,7 +2,7 @@ # Observer -`interface Observer` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L32) +`interface Observer` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L37) Interface to be implemented by classes that want to observe a media element. @@ -10,4 +10,5 @@ Interface to be implemented by classes that want to observe a media element. | Name | Summary | |---|---| +| [onMetadataChanged](on-metadata-changed.md) | `open fun onMetadataChanged(media: `[`Media`](../index.md)`, metadata: `[`Metadata`](../-metadata/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | | [onPlaybackStateChanged](on-playback-state-changed.md) | `open fun onPlaybackStateChanged(media: `[`Media`](../index.md)`, playbackState: `[`PlaybackState`](../-playback-state/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) | diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-metadata-changed.md b/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-metadata-changed.md new file mode 100644 index 00000000000..dcbbf516409 --- /dev/null +++ b/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-metadata-changed.md @@ -0,0 +1,5 @@ +[android-components](../../../index.md) / [mozilla.components.concept.engine.media](../../index.md) / [Media](../index.md) / [Observer](index.md) / [onMetadataChanged](./on-metadata-changed.md) + +# onMetadataChanged + +`open fun onMetadataChanged(media: `[`Media`](../index.md)`, metadata: `[`Metadata`](../-metadata/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L39) \ No newline at end of file diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-playback-state-changed.md b/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-playback-state-changed.md index 356be44e029..a1c96ffb3e9 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-playback-state-changed.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-observer/on-playback-state-changed.md @@ -2,4 +2,4 @@ # onPlaybackStateChanged -`open fun onPlaybackStateChanged(media: `[`Media`](../index.md)`, playbackState: `[`PlaybackState`](../-playback-state/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L33) \ No newline at end of file +`open fun onPlaybackStateChanged(media: `[`Media`](../index.md)`, playbackState: `[`PlaybackState`](../-playback-state/index.md)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L38) \ No newline at end of file diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-a-b-o-r-t.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-a-b-o-r-t.md index bf37fc64567..c01221270a2 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-a-b-o-r-t.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-a-b-o-r-t.md @@ -2,7 +2,7 @@ # ABORT -`ABORT` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L123) +`ABORT` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L129) Sent when playback is aborted; for example, if the media is playing and is restarted from the beginning, this event is sent. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-m-p-t-i-e-d.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-m-p-t-i-e-d.md index 835ed6ac4f7..98924b6297f 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-m-p-t-i-e-d.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-m-p-t-i-e-d.md @@ -2,7 +2,7 @@ # EMPTIED -`EMPTIED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L129) +`EMPTIED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L135) The media has become empty. For example, this event is sent if the media has already been loaded, and the load() method is called to reload it. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-n-d-e-d.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-n-d-e-d.md index 6dbd4c356e3..6451a7927e6 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-n-d-e-d.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-e-n-d-e-d.md @@ -2,7 +2,7 @@ # ENDED -`ENDED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L90) +`ENDED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L96) Sent when playback completes. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-a-u-s-e.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-a-u-s-e.md index 28af1aed419..b0cecb32378 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-a-u-s-e.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-a-u-s-e.md @@ -2,7 +2,7 @@ # PAUSE -`PAUSE` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L85) +`PAUSE` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L91) Sent when the playback state is changed to paused. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y-i-n-g.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y-i-n-g.md index 427c2358263..1f6ebe303e6 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y-i-n-g.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y-i-n-g.md @@ -2,7 +2,7 @@ # PLAYING -`PLAYING` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L80) +`PLAYING` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L86) Sent when the media has enough data to start playing, after the play event, but also when recovering from being stalled, when looping media restarts, and after seeked, if it was playing before seeking. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y.md index 437bd99608c..8235a8701c0 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-p-l-a-y.md @@ -2,7 +2,7 @@ # PLAY -`PLAY` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L74) +`PLAY` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L80) The media is no longer paused, as a result of the play method, or the autoplay attribute. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-e-d.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-e-d.md index da6fea4e08a..786258d7b71 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-e-d.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-e-d.md @@ -2,7 +2,7 @@ # SEEKED -`SEEKED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L100) +`SEEKED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L106) Sent when a seek operation completes. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-i-n-g.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-i-n-g.md index 6d5c926cee6..932da10b640 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-i-n-g.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-e-e-k-i-n-g.md @@ -2,7 +2,7 @@ # SEEKING -`SEEKING` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L95) +`SEEKING` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L101) Sent when a seek operation begins. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-t-a-l-l-e-d.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-t-a-l-l-e-d.md index b815d96322d..92d214afed8 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-t-a-l-l-e-d.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-t-a-l-l-e-d.md @@ -2,7 +2,7 @@ # STALLED -`STALLED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L105) +`STALLED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L111) Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-u-s-p-e-n-d-e-d.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-u-s-p-e-n-d-e-d.md index 1fc7277d137..9882f262cc9 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-u-s-p-e-n-d-e-d.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-s-u-s-p-e-n-d-e-d.md @@ -2,7 +2,7 @@ # SUSPENDED -`SUSPENDED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L111) +`SUSPENDED` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L117) Sent when loading of the media is suspended. This may happen either because the download has completed or because it has been paused for any other reason. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-u-n-k-n-o-w-n.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-u-n-k-n-o-w-n.md index 0379c4d5861..27f99cb945c 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-u-n-k-n-o-w-n.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-u-n-k-n-o-w-n.md @@ -2,7 +2,7 @@ # UNKNOWN -`UNKNOWN` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L69) +`UNKNOWN` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L75) Unknown. No state has been received from the engine yet. diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-w-a-i-t-i-n-g.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-w-a-i-t-i-n-g.md index 2a1cab89d64..81433b165cc 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-w-a-i-t-i-n-g.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/-w-a-i-t-i-n-g.md @@ -2,7 +2,7 @@ # WAITING -`WAITING` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L117) +`WAITING` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L123) Sent when the requested operation (such as playback) is delayed pending the completion of another operation (such as a seek). diff --git a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/index.md b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/index.md index abf8887e0ee..d35663d8bdd 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/index.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/-playback-state/index.md @@ -2,7 +2,7 @@ # PlaybackState -`enum class PlaybackState` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L65) +`enum class PlaybackState` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L71) ### Enum Values diff --git a/docs/api/mozilla.components.concept.engine.media/-media/index.md b/docs/api/mozilla.components.concept.engine.media/-media/index.md index 9636669ce2c..ef822d20b54 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/index.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/index.md @@ -11,6 +11,7 @@ Value type that represents a media element that is present on the currently disp | Name | Summary | |---|---| | [Controller](-controller/index.md) | `interface Controller`
    Controller for controlling playback of a media element. | +| [Metadata](-metadata/index.md) | `data class Metadata`
    Metadata associated with [Media](./index.md). | | [Observer](-observer/index.md) | `interface Observer`
    Interface to be implemented by classes that want to observe a media element. | | [PlaybackState](-playback-state/index.md) | `enum class PlaybackState` | @@ -25,6 +26,7 @@ Value type that represents a media element that is present on the currently disp | Name | Summary | |---|---| | [controller](controller.md) | `abstract val controller: `[`Controller`](-controller/index.md)
    The [Controller](-controller/index.md) for controlling playback of this media element. | +| [metadata](metadata.md) | `abstract val metadata: `[`Metadata`](-metadata/index.md)
    The [Metadata](-metadata/index.md) | | [playbackState](playback-state.md) | `var playbackState: `[`PlaybackState`](-playback-state/index.md)
    The current [PlaybackState](-playback-state/index.md) of this media element. | ### Functions diff --git a/docs/api/mozilla.components.concept.engine.media/-media/metadata.md b/docs/api/mozilla.components.concept.engine.media/-media/metadata.md new file mode 100644 index 00000000000..345eabc9ae9 --- /dev/null +++ b/docs/api/mozilla.components.concept.engine.media/-media/metadata.md @@ -0,0 +1,8 @@ +[android-components](../../index.md) / [mozilla.components.concept.engine.media](../index.md) / [Media](index.md) / [metadata](./metadata.md) + +# metadata + +`abstract val metadata: `[`Metadata`](-metadata/index.md) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L32) + +The [Metadata](-metadata/index.md) + diff --git a/docs/api/mozilla.components.concept.engine.media/-media/to-string.md b/docs/api/mozilla.components.concept.engine.media/-media/to-string.md index 0ba388ac4e4..5d29b6cb70d 100644 --- a/docs/api/mozilla.components.concept.engine.media/-media/to-string.md +++ b/docs/api/mozilla.components.concept.engine.media/-media/to-string.md @@ -2,4 +2,4 @@ # toString -`open fun toString(): `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L141) \ No newline at end of file +`open fun toString(): `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/concept/engine/src/main/java/mozilla/components/concept/engine/media/Media.kt#L156) \ No newline at end of file diff --git a/docs/api/mozilla.components.feature.media/-media-feature/enable.md b/docs/api/mozilla.components.feature.media/-media-feature/enable.md index 7d4e87d8285..92a9f3b7b50 100644 --- a/docs/api/mozilla.components.feature.media/-media-feature/enable.md +++ b/docs/api/mozilla.components.feature.media/-media-feature/enable.md @@ -2,7 +2,7 @@ # enable -`fun enable(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt#L30) +`fun enable(): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt#L36) Enables the feature. diff --git a/docs/api/mozilla.components.feature.media/-media-feature/index.md b/docs/api/mozilla.components.feature.media/-media-feature/index.md index 085e76dd8ea..7d7ab0203c1 100644 --- a/docs/api/mozilla.components.feature.media/-media-feature/index.md +++ b/docs/api/mozilla.components.feature.media/-media-feature/index.md @@ -2,7 +2,7 @@ # MediaFeature -`class MediaFeature` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt#L22) +`class MediaFeature` [(source)](https://github.com/mozilla-mobile/android-components/blob/master/components/feature/media/src/main/java/mozilla/components/feature/media/MediaFeature.kt#L23) Feature implementation for media playback in web content. This feature takes care of: From 221c54fdbbc82ef178b758e7d6d78f7b20b53272 Mon Sep 17 00:00:00 2001 From: Travis Long Date: Mon, 12 Aug 2019 08:11:55 -0500 Subject: [PATCH 19/38] Update worker cancel functions to be more like glean-core This updates the cancel functions that were recently added to cancel WorkManager workers when the metrics were disabled. This keeps glean-ac in line with the change requests for [this PR](https://github.com/mozilla/glean/pull/235) in Glean-Core. --- .../mozilla/components/service/glean/Glean.kt | 10 ++++------ .../glean/scheduler/MetricsPingScheduler.kt | 7 +++++++ .../glean/scheduler/PingUploadWorker.kt | 7 +++++++ .../scheduler/MetricsPingSchedulerTest.kt | 18 ++++++++++++++++++ .../glean/scheduler/PingUploadWorkerTest.kt | 17 +++++++++++++++++ 5 files changed, 53 insertions(+), 6 deletions(-) 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 580230b3643..af1e21b9027 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 @@ -10,7 +10,6 @@ import android.content.pm.PackageManager import android.os.Build import androidx.annotation.VisibleForTesting import androidx.lifecycle.ProcessLifecycleOwner -import androidx.work.WorkManager import kotlinx.coroutines.Job import kotlinx.coroutines.joinAll import mozilla.components.service.glean.GleanMetrics.GleanBaseline @@ -24,7 +23,6 @@ import mozilla.components.service.glean.ping.PingMaker import mozilla.components.service.glean.private.PingType import mozilla.components.service.glean.scheduler.GleanLifecycleObserver import mozilla.components.service.glean.scheduler.MetricsPingScheduler -import mozilla.components.service.glean.scheduler.MetricsPingWorker import mozilla.components.service.glean.scheduler.PingUploadWorker import mozilla.components.service.glean.storages.StorageEngineManager import mozilla.components.service.glean.storages.PingStorageEngine @@ -213,12 +211,12 @@ open class GleanInternalAPI internal constructor () { } /** - * Cancel any pending [PingUploadWorker] objects that have been enqueued. + * Cancel any pending [PingUploadWorker] objects that have been enqueued so that we don't + * accidentally upload or collect data after the upload has been disabled. */ private fun cancelPingWorkers() { - val workManager = WorkManager.getInstance() - workManager.cancelUniqueWork(PingUploadWorker.PING_WORKER_TAG) - workManager.cancelUniqueWork(MetricsPingWorker.TAG) + MetricsPingScheduler.cancel() + PingUploadWorker.cancel() } /** diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/MetricsPingScheduler.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/MetricsPingScheduler.kt index 8b22c0c8fc4..e20c7b181e6 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/MetricsPingScheduler.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/MetricsPingScheduler.kt @@ -51,6 +51,13 @@ internal class MetricsPingScheduler(val applicationContext: Context) : Lifecycle const val DUE_HOUR_OF_THE_DAY = 4 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal var isInForeground = false + + /** + * Function to cancel any pending metrics ping workers + */ + internal fun cancel() { + WorkManager.getInstance().cancelUniqueWork(MetricsPingWorker.TAG) + } } init { diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt index fdfdfcce37e..d8b80388266 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/PingUploadWorker.kt @@ -67,6 +67,13 @@ class PingUploadWorker(context: Context, params: WorkerParameters) : Worker(cont val httpPingUploader = HttpPingUploader() return Glean.pingStorageEngine.process(httpPingUploader::upload) } + + /** + * Function to cancel any pending ping upload workers + */ + internal fun cancel() { + WorkManager.getInstance().cancelUniqueWork(PING_WORKER_TAG) + } } /** diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/MetricsPingSchedulerTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/MetricsPingSchedulerTest.kt index b9ddcc98a8d..e1a085d52b2 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/MetricsPingSchedulerTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/MetricsPingSchedulerTest.kt @@ -459,6 +459,24 @@ class MetricsPingSchedulerTest { assertTrue(getWorkerStatus(MetricsPingWorker.TAG).isEnqueued) } + @Test + fun `cancel() correctly cancels worker`() { + val mps = MetricsPingScheduler(ApplicationProvider.getApplicationContext()) + + mps.schedulePingCollection(Calendar.getInstance(), true) + + // Verify that the worker is enqueued + assertTrue("MetricsPingWorker is enqueued", + getWorkerStatus(MetricsPingWorker.TAG).isEnqueued) + + // Cancel the worker + MetricsPingScheduler.cancel() + + // Verify worker has been cancelled + assertFalse("MetricsPingWorker is not enqueued", + getWorkerStatus(MetricsPingWorker.TAG).isEnqueued) + } + // @Test // fun `Glean should close the measurement window for overdue pings before recording new data`() { // // This test is a bit tricky: we want to make sure that, when our metrics ping is overdue diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/PingUploadWorkerTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/PingUploadWorkerTest.kt index 043eabe88e9..802954f3910 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/PingUploadWorkerTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/PingUploadWorkerTest.kt @@ -6,6 +6,7 @@ import androidx.work.BackoffPolicy import androidx.work.NetworkType import androidx.work.WorkerParameters import mozilla.components.service.glean.config.Configuration +import mozilla.components.service.glean.getWorkerStatus import mozilla.components.service.glean.resetGlean import org.junit.Assert import org.junit.Before @@ -50,4 +51,20 @@ class PingUploadWorkerTest { val result = pingUploadWorker!!.doWork() Assert.assertTrue(result.toString().contains("Success")) } + + @Test + fun `cancel() correctly cancels worker`() { + PingUploadWorker.enqueueWorker() + + // Verify that the worker is enqueued + Assert.assertTrue("PingUploadWorker is enqueued", + getWorkerStatus(PingUploadWorker.PING_WORKER_TAG).isEnqueued) + + // Cancel the worker + PingUploadWorker.cancel() + + // Verify worker has been cancelled + Assert.assertFalse("PingUploadWorker is not enqueued", + getWorkerStatus(PingUploadWorker.PING_WORKER_TAG).isEnqueued) + } } From 2cc3aed61c5daf5a4184e1a3fffd311bd99371df Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Mon, 12 Aug 2019 15:19:27 +0200 Subject: [PATCH 20/38] Issue #1200: Add configuration for bors. --- bors.toml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 bors.toml diff --git a/bors.toml b/bors.toml new file mode 100644 index 00000000000..a4e039ceafc --- /dev/null +++ b/bors.toml @@ -0,0 +1,12 @@ +status = [ + "Taskcluster (push)" +] +block_labels = [ + "blocked", + "work in progress" +] +[committer] +name = "MickeyMoz" +email = "sebastian@mozilla.com" +required_approvals = 1 +delete_merged_branches = true From 934bbcf891c9c10a006071fe813ee7b106dc152d Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Mon, 12 Aug 2019 14:10:48 +0000 Subject: [PATCH 21/38] Update GeckoView (beta) (20190812-141047) --- buildSrc/src/main/java/Gecko.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Gecko.kt b/buildSrc/src/main/java/Gecko.kt index 87d286ad00e..800695a0413 100644 --- a/buildSrc/src/main/java/Gecko.kt +++ b/buildSrc/src/main/java/Gecko.kt @@ -11,7 +11,7 @@ internal object GeckoVersions { /** * GeckoView Beta Version. */ - const val beta_version = "69.0.20190808090046" + const val beta_version = "69.0.20190812090043" /** * GeckoView Release Version. From 284b533ffe5537fa03ef78db0c8737772a4d3f85 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Mon, 12 Aug 2019 17:09:10 +0200 Subject: [PATCH 22/38] Issue #1200: .taskcluster.yml: Special case bors bot user. --- .taskcluster.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.taskcluster.yml b/.taskcluster.yml index d9be145d62d..11b0bae78c9 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -9,7 +9,11 @@ tasks: $let: decision_task_id: {$eval: as_slugid("decision_task")} expires_in: {$fromNow: '1 year'} - user: ${event.sender.login} + user: + # GitHub adds "[bot]" to bot usernames and that doesn't validate as email. + $if: 'event.sender.login == "bors[bot]"' + then: bors + else: ${event.sender.login} # We define the following variable at the very top, because they are used in the # default definition From 780444a268191056eedaad0146ec9941cffbe699 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 5 Aug 2019 19:01:54 -0400 Subject: [PATCH 23/38] 1564989: Implement a functional mapping for timing distributions --- components/service/glean/build.gradle | 2 +- .../private/TimingDistributionMetricType.kt | 6 +- .../TimingDistributionsStorageEngine.kt | 288 ++++++++---------- .../TimingDistributionMetricTypeTest.kt | 4 +- .../TimingDistributionsStorageEngineTest.kt | 179 ++++------- 5 files changed, 191 insertions(+), 288 deletions(-) diff --git a/components/service/glean/build.gradle b/components/service/glean/build.gradle index dbc244f9818..607623aea01 100644 --- a/components/service/glean/build.gradle +++ b/components/service/glean/build.gradle @@ -14,7 +14,7 @@ apply plugin: 'kotlin-android' * created during unit testing. * This uses a specific version of the schema identified by a git commit hash. */ -String GLEAN_PING_SCHEMA_GIT_HASH = "64b852c" +String GLEAN_PING_SCHEMA_GIT_HASH = "73c5a65" String GLEAN_PING_SCHEMA_URL = "https://raw.githubusercontent.com/mozilla-services/mozilla-pipeline-schemas/$GLEAN_PING_SCHEMA_GIT_HASH/schemas/glean/baseline/baseline.1.schema.json" android { diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt index e77d9785d21..d5eb261c895 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt @@ -63,8 +63,7 @@ data class TimingDistributionMetricType( // Delegate storing the string to the storage engine. TimingDistributionsStorageEngine.accumulate( metricData = this@TimingDistributionMetricType, - sample = elapsedNanos, - timeUnit = timeUnit + sample = elapsedNanos ) } } @@ -94,8 +93,7 @@ data class TimingDistributionMetricType( Dispatchers.API.launch { TimingDistributionsStorageEngine.accumulateSamples( metricData = this@TimingDistributionMetricType, - samples = samples, - timeUnit = timeUnit + samples = samples ) } } diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt index 1df619c2d1a..0141f8fd828 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt @@ -9,16 +9,14 @@ import android.content.SharedPreferences import androidx.annotation.VisibleForTesting import mozilla.components.service.glean.error.ErrorRecording import mozilla.components.service.glean.private.CommonMetricData -import mozilla.components.service.glean.private.HistogramType -import mozilla.components.service.glean.private.TimeUnit -import mozilla.components.service.glean.utils.getAdjustedTime import mozilla.components.support.base.log.logger.Logger -import mozilla.components.support.ktx.android.org.json.tryGetInt import mozilla.components.support.ktx.android.org.json.tryGetLong import mozilla.components.support.ktx.android.org.json.tryGetString -import org.json.JSONArray import org.json.JSONObject +import java.lang.Math.log +import java.lang.Math.pow +import kotlin.math.log /** * This singleton handles the in-memory storage logic for timing distributions. It is meant to be @@ -35,6 +33,11 @@ internal open class TimingDistributionsStorageEngineImplementation( override val logger: Logger = Logger("glean/TimingDistributionsStorageEngine") ) : GenericStorageEngine() { + companion object { + // Maximum time of 10 minutes in nanoseconds + internal const val MAX_SAMPLE_TIME: Long = 1000L * 1000L * 1000L * 60L * 10L + } + override fun deserializeSingleMetric(metricName: String, value: Any?): TimingDistributionData? { return try { (value as? String)?.let { @@ -60,47 +63,40 @@ internal open class TimingDistributionsStorageEngineImplementation( * * @param metricData the metric information for the timing distribution * @param sample the value to accumulate, in nanoseconds - * @param timeUnit the [TimeUnit] the sample will be converted to */ @Synchronized fun accumulate( metricData: CommonMetricData, - sample: Long, - timeUnit: TimeUnit + sample: Long ) { - // We're checking for errors in `accumulateSamples` already, but - // we need to check it here too anyway because `getAdjustedTime` would - // throw otherwise. - if (sample < 0) { - ErrorRecording.recordError( - metricData, - ErrorRecording.ErrorType.InvalidValue, - "Accumulate negative $sample", - logger - ) - return - } - - val sampleInUnit = getAdjustedTime(timeUnit, sample) - accumulateSamples(metricData, longArrayOf(sampleInUnit), timeUnit) + accumulateSamples(metricData, longArrayOf(sample)) } /** * Accumulate an array of samples for the provided metric. * * @param metricData the metric information for the timing distribution - * @param samples the values to accumulate, provided in the metric's [TimeUnit] (they won't - * be truncated nor converted) - * @param timeUnit the [TimeUnit] the samples are in + * @param samples the values to accumulate, in nanoseconds */ @Synchronized fun accumulateSamples( metricData: CommonMetricData, - samples: LongArray, - timeUnit: TimeUnit + samples: LongArray ) { - val validSamples = samples.filter { sample -> sample >= 0 } - val numNegativeSamples = samples.size - validSamples.size + var numTooLongSamples = 0 + var numNegativeSamples = 0 + val validSamples = samples.map { sample -> + if (sample < 0) { + numNegativeSamples += 1 + 0 + } else if (sample > MAX_SAMPLE_TIME) { + numTooLongSamples += 1 + MAX_SAMPLE_TIME + } else { + sample + } + } + if (numNegativeSamples > 0) { ErrorRecording.recordError( metricData, @@ -109,22 +105,32 @@ internal open class TimingDistributionsStorageEngineImplementation( logger, numNegativeSamples ) + // Negative samples indicate a serious and unexpected error, so don't record anything return } + if (numTooLongSamples > 0) { + ErrorRecording.recordError( + metricData, + ErrorRecording.ErrorType.InvalidValue, + "Accumulate $numTooLongSamples samples longer than 10 minutes", + logger, + numTooLongSamples + ) + // Too long samples should just be truncated, but otherwise we deal record and handle them + } + // Since the custom combiner closure captures this value, we need to just create a dummy // value here that won't be used by the combine function, and create a fresh // TimingDistributionData for each value that doesn't have an existing current value. - val dummy = TimingDistributionData(category = metricData.category, name = metricData.name, - timeUnit = timeUnit) + val dummy = TimingDistributionData(category = metricData.category, name = metricData.name) validSamples.forEach { sample -> super.recordMetric(metricData, dummy, null) { currentValue, _ -> currentValue?.let { it.accumulate(sample) it } ?: let { - val newTD = TimingDistributionData(category = metricData.category, name = metricData.name, - timeUnit = timeUnit) + val newTD = TimingDistributionData(category = metricData.category, name = metricData.name) newTD.accumulate(sample) return@let newTD } @@ -154,38 +160,69 @@ internal open class TimingDistributionsStorageEngineImplementation( /** * This class represents the structure of a timing distribution according to the pipeline schema. It * is meant to help serialize and deserialize data to the correct format for transport and storage, - * as well as including a helper function to calculate the bucket sizes. + * as well as performing the calculations to determine the correct bucket for each sample. + * + * The bucket index of a given sample is determined with the following function: + * + * i = ⌊n log₂(𝑥)⌋ + * + * In other words, there are n buckets for each power of 2 magnitude. + * + * The value of 8 for n was determined experimentally based on existing data to have sufficient + * resolution. + * + * Samples greater than 10 minutes in length are truncated to 10 minutes. * * @param category of the metric * @param name of the metric - * @param bucketCount total number of buckets - * @param rangeMin the minimum value that can be represented - * @param rangeMax the maximum value that can be represented - * @param histogramType the [HistogramType] representing the bucket layout - * @param values a map containing the bucket index mapped to the accumulated count + * @param values a map containing the minimum bucket value mapped to the accumulated count * @param sum the accumulated sum of all the samples in the timing distribution - * @param timeUnit the base [TimeUnit] of the bucket values */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) data class TimingDistributionData( val category: String, val name: String, - val bucketCount: Int = DEFAULT_BUCKET_COUNT, - val rangeMin: Long = DEFAULT_RANGE_MIN, - val rangeMax: Long = DEFAULT_RANGE_MAX, - val histogramType: HistogramType = HistogramType.Exponential, // map from bucket limits to accumulated values val values: MutableMap = mutableMapOf(), - var sum: Long = 0, - val timeUnit: TimeUnit = TimeUnit.Millisecond + var sum: Long = 0 ) { companion object { - // The following are defaults for a simple timing distribution for the default time unit - // of millisecond. The values arrived at were an approximated using existing "_MS" - // telemetry probes as a guide. - const val DEFAULT_BUCKET_COUNT = 100 - const val DEFAULT_RANGE_MIN = 0L - const val DEFAULT_RANGE_MAX = 60000L + // The base of the logarithm used to determine bucketing + internal const val LOG_BASE = 2.0 + + // The buckets per each order of magnitude of the logarithm. + internal const val BUCKETS_PER_MAGNITUDE = 8.0 + + // The combined log base and buckets per magnitude. + internal val EXPONENT = pow(LOG_BASE, 1.0 / BUCKETS_PER_MAGNITUDE) + + /** + * Maps a sample to a "bucket index" that it belongs in. + * A "bucket index" is the consecutive integer index of each bucket, useful as a + * mathematical concept, even though the internal representation is stored and + * sent using the minimum value in each bucket. + */ + internal fun sampleToBucketIndex(sample: Long): Long { + return log(sample.toDouble() + 1, EXPONENT).toLong() + } + + /** + * Determines the minimum value of a bucket, given a bucket index. + */ + internal fun bucketIndexToBucketMinimum(bucketIndex: Long): Long { + return pow(EXPONENT, bucketIndex.toDouble()).toLong() + } + + /** + * Maps a sample to the minimum value of the bucket it belongs in. + */ + internal fun sampleToBucketMinimum(sample: Long): Long { + return if (sample == 0L) { + 0L + } else { + bucketIndexToBucketMinimum(sampleToBucketIndex(sample)) + } + } /** * Factory function that takes stringified JSON and converts it back into a @@ -209,37 +246,21 @@ data class TimingDistributionData( // something is wrong and we should return null. val category = jsonObject.tryGetString("category").orEmpty() val name = jsonObject.tryGetString("name") ?: return null - val bucketCount = jsonObject.tryGetInt("bucket_count") ?: return null - // If 'range' isn't present, JSONException is thrown - val range = try { - val array = jsonObject.getJSONArray("range") - // Range must have exactly 2 values - if (array.length() == 2) { - // The getLong() function throws JSONException if we can't convert to a Long, so - // the catch should return null if either value isn't a valid Long - array.getLong(0) - array.getLong(1) - // This returns the JSONArray to the assignment if everything checks out - array - } else { - return null - } - } catch (e: org.json.JSONException) { - return null - } - val rawHistogramType = jsonObject.tryGetString("histogram_type") ?: return null - val histogramType = try { - HistogramType.valueOf(rawHistogramType.capitalize()) - } catch (e: IllegalArgumentException) { - return null - } // Attempt to parse the values map, if it fails then something is wrong and we need to // return null. val values = try { val mapData = jsonObject.getJSONObject("values") val valueMap: MutableMap = mutableMapOf() mapData.keys().forEach { key -> - valueMap[key.toLong()] = mapData.tryGetLong(key) ?: 0L + mapData.tryGetLong(key)?.let { + // Don't restore buckets with zero values. They are unnecessary, + // and it also makes it easier to determine the contiguous range of + // buckets that we need to fill in the ping when we send it out if + // we can assume the values map never as 0 values. + if (it != 0L) { + valueMap[key.toLong()] = it + } + } } valueMap } catch (e: org.json.JSONException) { @@ -247,23 +268,12 @@ data class TimingDistributionData( return null } val sum = jsonObject.tryGetLong("sum") ?: return null - val rawTimeUnit = jsonObject.tryGetString("time_unit") ?: return null - val timeUnit = try { - TimeUnit.valueOf(rawTimeUnit.capitalize()) - } catch (e: IllegalArgumentException) { - return null - } return TimingDistributionData( category = category, name = name, - bucketCount = bucketCount, - rangeMin = range.getLong(0), - rangeMax = range.getLong(1), - histogramType = histogramType, values = values, - sum = sum, - timeUnit = timeUnit + sum = sum ) } } @@ -276,37 +286,15 @@ data class TimingDistributionData( // blank categories internal val identifier: String = if (category.isEmpty()) { name } else { "$category.$name" } - // This is a list of limits for the buckets. Instantiated lazily to ensure that the range and - // bucket counts are set first. - internal val buckets: List by lazy { getBuckets() } - /** - * Accumulates a sample to the correct bucket, using a binary search to locate the index of the - * bucket where the sample is bigger than or equal to the bucket limit. + * Accumulates a sample to the correct bucket. * If a value doesn't exist for this bucket yet, one is created. * * @param sample Long value representing the sample that is being accumulated */ internal fun accumulate(sample: Long) { - var under = 0 - var over = bucketCount - var mid: Int - - do { - mid = under + (over - under) / 2 - if (mid == under) { - break - } - - if (buckets[mid] <= sample) { - under = mid - } else { - over = mid - } - } while (true) - - val limit = buckets[mid] - values[limit] = (values[limit] ?: 0) + 1 + var bucketMinimum = sampleToBucketMinimum(sample) + values[bucketMinimum] = (values[bucketMinimum] ?: 0) + 1 sum += sample } @@ -315,55 +303,33 @@ data class TimingDistributionData( * purposes. */ internal fun toJsonObject(): JSONObject { - return JSONObject(mapOf( - "category" to category, - "name" to name, - "bucket_count" to bucketCount, - "range" to JSONArray(arrayOf(rangeMin, rangeMax)), - "histogram_type" to histogramType.toString().toLowerCase(), - "values" to values.mapKeys { "${it.key}" }, - "sum" to sum, - "time_unit" to timeUnit.toString().toLowerCase() - )) - } - - /** - * Helper function to generate the list of bucket max values used when accumulating to the - * correct buckets. - * - * @return List containing the bucket limits - */ - private fun getBuckets(): List { - // This algorithm calculates the bucket sizes using a natural log approach to get - // `bucketCount` number of buckets, exponentially spaced between `range[MIN]` and - // `range[MAX]`. - // - // Bucket limits are the minimal bucket value. - // That means values in a bucket `i` are `range[i] <= value < range[i+1]`. - // It will always contain an underflow bucket (`< 1`). - val logMax = Math.log(rangeMax.toDouble()) - val result: MutableList = mutableListOf() - var current = rangeMin - if (current == 0L) { - current = 1L - } + val completeValues = if (values.size != 0) { + // A bucket range is defined by its own key, and the key of the next + // highest bucket. This emplicitly adds any empty buckets (even if they have values + // of 0) between the lowest and highest bucket so that the backend knows the + // bucket ranges even without needing to know that function that was used to + // create the buckets. + val minBucket = sampleToBucketIndex(values.keys.min()!!) + val maxBucket = sampleToBucketIndex(values.keys.max()!!) + 1 - // underflow bucket - result.add(0) - result.add(current) + var completeValues: MutableMap = mutableMapOf() - for (i in 2 until bucketCount) { - val logCurrent = Math.log(current.toDouble()) - val logRatio = (logMax - logCurrent) / (bucketCount - i) - val logNext = logCurrent + logRatio - val nextValue = Math.round(Math.exp(logNext)) - if (nextValue > current) { - current = nextValue - } else { - ++current + for (i in minBucket..maxBucket) { + val bucketMinimum = bucketIndexToBucketMinimum(i) + val bucketSum = values.get(bucketMinimum)?.let { it } ?: 0 + completeValues[bucketMinimum.toString()] = bucketSum } - result.add(current) + + completeValues + } else { + values } - return result.sorted() + + return JSONObject(mapOf( + "category" to category, + "name" to name, + "values" to completeValues, + "sum" to sum + )) } } diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt index 8fc72106f99..433e4547057 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt @@ -48,7 +48,7 @@ class TimingDistributionMetricTypeTest { for (i in 1L..3L) { TimingManager.getElapsedNanos = { 0 } val timerId = metric.start() - TimingManager.getElapsedNanos = { i * 1000000 } // ms to ns + TimingManager.getElapsedNanos = { i } metric.stopAndAccumulate(timerId) } @@ -119,7 +119,7 @@ class TimingDistributionMetricTypeTest { for (i in 1L..3L) { TimingManager.getElapsedNanos = { 0 } val timerId = metric.start() - TimingManager.getElapsedNanos = { i * 1000000 } // ms to ns + TimingManager.getElapsedNanos = { i } metric.stopAndAccumulate(timerId) } diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngineTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngineTest.kt index 2734e9e3aab..961e269a1ca 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngineTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngineTest.kt @@ -20,13 +20,13 @@ import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers import org.mockito.Mockito import org.robolectric.RobolectricTestRunner +import java.lang.Math.pow @RunWith(RobolectricTestRunner::class) class TimingDistributionsStorageEngineTest { @@ -39,6 +39,28 @@ class TimingDistributionsStorageEngineTest { TimingManager.testResetTimeSource() } + @Test + fun `sampleToBucketMinimum correctly rounds down`() { + // Check each of the first 100 integers, where numerical accuracy of the round-tripping + // is most potentially problematic + for (i in (0..100)) { + val value = i.toLong() + val bucketMinimum = TimingDistributionData.sampleToBucketMinimum(value) + assert(bucketMinimum <= value) + + assertEquals(bucketMinimum, TimingDistributionData.sampleToBucketMinimum(bucketMinimum)) + } + + // Do an exponential sampling of higher numbers + for (i in (11..500)) { + val value = pow(1.5, i.toDouble()).toLong() + val bucketMinimum = TimingDistributionData.sampleToBucketMinimum(value) + assert(bucketMinimum <= value) + + assertEquals(bucketMinimum, TimingDistributionData.sampleToBucketMinimum(bucketMinimum)) + } + } + @Test fun `accumulate() properly updates the values in all stores`() { val storeNames = listOf("store1", "store2") @@ -57,8 +79,7 @@ class TimingDistributionsStorageEngineTest { val sample = 1L TimingDistributionsStorageEngine.accumulate( metricData = metric, - sample = sample, - timeUnit = metric.timeUnit + sample = sample ) // Check that the data was correctly set in each store. @@ -68,7 +89,7 @@ class TimingDistributionsStorageEngineTest { clearStore = true ) assertEquals(1, snapshot!!.size) - assertEquals(1L, snapshot["telemetry.test_timing_distribution"]?.values!![0]) + assertEquals(1L, snapshot["telemetry.test_timing_distribution"]?.values!![1]) } } @@ -93,14 +114,9 @@ class TimingDistributionsStorageEngineTest { "store1#telemetry.invalid_int" to -1, "store1#telemetry.invalid_list" to listOf("1", "2", "3"), "store1#telemetry.invalid_int_list" to "[1,2,3]", - "store1#telemetry.invalid_td_name" to "{\"category\":\"telemetry\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_bucket_count" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":\"not an int!\",\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_range" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_range2" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":100,\"range\":[\"not\",\"numeric\"],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_histogram_type" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":-1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_values" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{\"0\": \"nope\"},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_sum" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":\"nope\",\"time_unit\":2}", - "store1#telemetry.invalid_td_time_unit" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":-1}", + "store1#telemetry.invalid_td_name" to "{\"category\":\"telemetry\",\"values\":{},\"sum\":0}", + "store1#telemetry.invalid_td_values" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"values\":{\"0\": \"nope\"},\"sum\":0}", + "store1#telemetry.invalid_td_sum" to "{\"category\":\"telemetry\",\"name\":\"test_timing_distribution\",\"values\":{},\"sum\":\"nope\"}", "store1#telemetry.test_timing_distribution" to td.toJsonObject().toString() ) @@ -169,13 +185,12 @@ class TimingDistributionsStorageEngineTest { // Using the TimingDistributionData object here to easily turn the object into JSON // for comparison purposes. val td = TimingDistributionData(category = metric.category, name = metric.name) - td.accumulate(1L) + td.accumulate(1000000L) runBlocking { storageEngine.accumulate( metricData = metric, - sample = 1000000L, - timeUnit = metric.timeUnit + sample = 1000000L ) } @@ -194,7 +209,7 @@ class TimingDistributionsStorageEngineTest { storageEngine.applicationContext = ApplicationProvider.getApplicationContext() val td = TimingDistributionData(category = "telemetry", name = "test_timing_distribution") - td.accumulate(1L) + td.accumulate(1000000L) // Get snapshot from store1 val json = storageEngine.getSnapshotAsJSON("store1", true) @@ -232,35 +247,6 @@ class TimingDistributionsStorageEngineTest { ErrorRecording.testGetNumRecordedErrors(metric, ErrorRecording.ErrorType.InvalidValue)) } - @Test - fun `underflow values accumulate in the first bucket`() { - // Define a timing distribution metric, which will be stored in "store1". - val metric = TimingDistributionMetricType( - disabled = false, - category = "telemetry", - lifetime = Lifetime.User, - name = "test_timing_distribution", - sendInPings = listOf("store1"), - timeUnit = TimeUnit.Millisecond - ) - - // Attempt to accumulate an overflow sample - TimingManager.getElapsedNanos = { 0 } - val timerId = metric.start() - TimingManager.getElapsedNanos = { 0 } - metric.stopAndAccumulate(timerId) - - // Check that timing distribution was recorded. - assertTrue("Accumulating underflow values records data", - metric.testHasValue()) - - // Make sure that the underflow landed in the correct (first) bucket - val snapshot = metric.testGetValue() - assertEquals("Accumulating overflow values should increment underflow bucket", - 1L, - snapshot.values[0]) - } - @Test fun `overflow values accumulate in the last bucket`() { // Define a timing distribution metric, which will be stored in "store1". @@ -276,7 +262,7 @@ class TimingDistributionsStorageEngineTest { // Attempt to accumulate an overflow sample TimingManager.getElapsedNanos = { 0 } val timerId = metric.start() - TimingManager.getElapsedNanos = { (TimingDistributionData.DEFAULT_RANGE_MAX + 100) * 1000000 } + TimingManager.getElapsedNanos = { TimingDistributionsStorageEngineImplementation.MAX_SAMPLE_TIME * 2 } metric.stopAndAccumulate(timerId) // Check that timing distribution was recorded. @@ -287,50 +273,7 @@ class TimingDistributionsStorageEngineTest { val snapshot = metric.testGetValue() assertEquals("Accumulating overflow values should increment last bucket", 1L, - snapshot.values[TimingDistributionData.DEFAULT_RANGE_MAX]) - } - - @Test - fun `getBuckets() correctly populates the buckets property`() { - // Hand calculated values using current default range 0 - 60000 and bucket count of 100. - // NOTE: The final bucket, regardless of width, represents the overflow bucket to hold any - // values beyond the maximum (in this case the maximum is 60000) - val testBuckets: List = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, - 19, 21, 23, 25, 28, 31, 34, 38, 42, 46, 51, 56, 62, 68, 75, 83, 92, 101, 111, 122, 135, - 149, 164, 181, 200, 221, 244, 269, 297, 328, 362, 399, 440, 485, 535, 590, 651, 718, - 792, 874, 964, 1064, 1174, 1295, 1429, 1577, 1740, 1920, 2118, 2337, 2579, 2846, 3140, - 3464, 3822, 4217, 4653, 5134, 5665, 6250, 6896, 7609, 8395, 9262, 10219, 11275, 12440, - 13726, 15144, 16709, 18436, 20341, 22443, 24762, 27321, 30144, 33259, 36696, 40488, - 44672, 49288, 54381, 60000) - - // Define a timing distribution metric, which will be stored in "store1". - val metric = TimingDistributionMetricType( - disabled = false, - category = "telemetry", - lifetime = Lifetime.User, - name = "test_timing_distribution", - sendInPings = listOf("store1"), - timeUnit = TimeUnit.Millisecond - ) - - // Accumulate a sample to force the lazy loading of `buckets` to occur - TimingManager.getElapsedNanos = { 0 } - val timerId = metric.start() - TimingManager.getElapsedNanos = { 1 } - metric.stopAndAccumulate(timerId) - - // Check that timing distribution was recorded. - assertTrue("Accumulating values records data", metric.testHasValue()) - - // Make sure that the sample in the correct (underflow) bucket - val snapshot = metric.testGetValue() - assertEquals("Accumulating should increment correct bucket", - 1L, snapshot.values[0]) - - // verify buckets lists worked - assertNotNull("Buckets must not be null", snapshot.buckets) - - assertEquals("Bucket calculation failed", testBuckets, snapshot.buckets) + snapshot.values[TimingDistributionData.sampleToBucketMinimum(TimingDistributionsStorageEngineImplementation.MAX_SAMPLE_TIME)]) } @Test @@ -345,14 +288,13 @@ class TimingDistributionsStorageEngineTest { timeUnit = TimeUnit.Millisecond ) - // Check that a few values correctly fall into the correct buckets (as calculated by hand) - // to validate the linear bucket search algorithm + val samples = listOf(10L, 100L, 1000L, 10000L) // Attempt to accumulate a sample to force metric to be stored - for (i in listOf(1L, 10L, 100L, 1000L, 10000L)) { + for (i in samples) { TimingManager.getElapsedNanos = { 0 } val timerId = metric.start() - TimingManager.getElapsedNanos = { i * 1000000 } // Convert ms to ns + TimingManager.getElapsedNanos = { i } metric.stopAndAccumulate(timerId) } @@ -363,19 +305,27 @@ class TimingDistributionsStorageEngineTest { val snapshot = metric.testGetValue() // Check sum and count - assertEquals("Accumulating updates the sum", 11111, snapshot.sum) - assertEquals("Accumulating updates the count", 5, snapshot.count) - - assertEquals("Accumulating should increment correct bucket", - 1L, snapshot.values[1]) - assertEquals("Accumulating should increment correct bucket", - 1L, snapshot.values[10]) - assertEquals("Accumulating should increment correct bucket", - 1L, snapshot.values[92]) - assertEquals("Accumulating should increment correct bucket", - 1L, snapshot.values[964]) - assertEquals("Accumulating should increment correct bucket", - 1L, snapshot.values[9262]) + assertEquals("Accumulating updates the sum", 11110, snapshot.sum) + assertEquals("Accumulating updates the count", 4, snapshot.count) + + for (i in samples) { + val binEdge = TimingDistributionData.sampleToBucketMinimum(i) + assertEquals("Accumulating should increment correct bucket", 1L, snapshot.values[binEdge]) + } + + val json = snapshot.toJsonObject() + val values = json.getJSONObject("values") + assertEquals(81, values.length()) + + for (i in samples) { + val binEdge = TimingDistributionData.sampleToBucketMinimum(i) + assertEquals("Accumulating should increment correct bucket", 1L, values.getLong(binEdge.toString())) + values.remove(binEdge.toString()) + } + + for (k in values.keys()) { + assertEquals(0L, values.getLong(k)) + } } @Test @@ -396,27 +346,16 @@ class TimingDistributionsStorageEngineTest { "telemetry", jsonTdd.getString("category")) assertEquals("JSON name must match Timing Distribution name", "test_timing_distribution", jsonTdd.getString("name")) - assertEquals("JSON bucket count must match Timing Distribution bucket count", - tdd.bucketCount, jsonTdd.getInt("bucket_count")) assertEquals("JSON name must match Timing Distribution name", "test_timing_distribution", jsonTdd.getString("name")) - val jsonRange = jsonTdd.getJSONArray("range") - assertEquals("JSON range minimum must match Timing Distribution range minimum", - tdd.rangeMin, jsonRange.getLong(0)) - assertEquals("JSON range maximum must match Timing Distribution range maximum", - tdd.rangeMax, jsonRange.getLong(1)) - assertEquals("JSON histogram type must match Timing Distribution histogram type", - tdd.histogramType.toString().toLowerCase(), jsonTdd.getString("histogram_type")) val jsonValue = jsonTdd.getJSONObject("values") assertEquals("JSON values must match Timing Distribution values", tdd.values[1], jsonValue.getLong("1")) - assertEquals("JSON values must match Timing Distribution values", - tdd.values[2], jsonValue.getLong("2")) assertEquals("JSON values must match Timing Distribution values", tdd.values[3], jsonValue.getLong("3")) + assertEquals("JSON values must match Timing Distribution values", + 0, jsonValue.getLong("4")) assertEquals("JSON sum must match Timing Distribution sum", tdd.sum, jsonTdd.getLong("sum")) - assertEquals("JSON time unit must match Timing Distribution time unit", - tdd.timeUnit.toString().toLowerCase(), jsonTdd.getString("time_unit")) } } From 3d6ef14b727c89c70c49ba8f20d007649a016f30 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Aug 2019 09:24:41 -0400 Subject: [PATCH 24/38] Return unit conversion semantics for GV code path --- .../private/TimingDistributionMetricType.kt | 3 ++- .../TimingDistributionsStorageEngine.kt | 21 +++++++++++++------ .../service/glean/utils/TimeUtils.kt | 20 ++++++++++++++++++ .../TimingDistributionMetricTypeTest.kt | 17 +++++++++++---- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt index d5eb261c895..666bdd649f9 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt @@ -93,7 +93,8 @@ data class TimingDistributionMetricType( Dispatchers.API.launch { TimingDistributionsStorageEngine.accumulateSamples( metricData = this@TimingDistributionMetricType, - samples = samples + samples = samples, + timeUnit = timeUnit ) } } diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt index 0141f8fd828..6cc9c56ea6d 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt @@ -9,6 +9,8 @@ import android.content.SharedPreferences import androidx.annotation.VisibleForTesting import mozilla.components.service.glean.error.ErrorRecording import mozilla.components.service.glean.private.CommonMetricData +import mozilla.components.service.glean.private.TimeUnit +import mozilla.components.service.glean.utils.timeToNanos import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.ktx.android.org.json.tryGetLong @@ -76,24 +78,31 @@ internal open class TimingDistributionsStorageEngineImplementation( * Accumulate an array of samples for the provided metric. * * @param metricData the metric information for the timing distribution - * @param samples the values to accumulate, in nanoseconds + * @param samples the values to accumulate, in the given `timeUnit` + * @param timeUnit the unit that the given samples are in, defaults to nanoseconds */ @Synchronized fun accumulateSamples( metricData: CommonMetricData, - samples: LongArray + samples: LongArray, + timeUnit: TimeUnit = TimeUnit.Nanosecond ) { + // Remove invalid samples, and convert to nanos var numTooLongSamples = 0 var numNegativeSamples = 0 + var factor = timeToNanos(timeUnit, 1) val validSamples = samples.map { sample -> if (sample < 0) { numNegativeSamples += 1 0 - } else if (sample > MAX_SAMPLE_TIME) { - numTooLongSamples += 1 - MAX_SAMPLE_TIME } else { - sample + val sampleInNanos = sample * factor + if (sampleInNanos > MAX_SAMPLE_TIME) { + numTooLongSamples += 1 + MAX_SAMPLE_TIME + } else { + sampleInNanos + } } } diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/utils/TimeUtils.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/utils/TimeUtils.kt index d1c1765e3cb..8437725f01d 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/utils/TimeUtils.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/utils/TimeUtils.kt @@ -26,3 +26,23 @@ internal fun getAdjustedTime(timeUnit: TimeUnit, elapsedNanos: Long): Long { TimeUnit.Day -> AndroidTimeUnit.NANOSECONDS.toDays(elapsedNanos) } } + +/** + * Convenience method to get a time in a different unit to nanoseconds. + * + * @param timeUnit the unit the value is in + * @param value a time in the given unit + * + * @return the time, in nanoseconds + */ +internal fun timeToNanos(timeUnit: TimeUnit, value: Long): Long { + return when (timeUnit) { + TimeUnit.Nanosecond -> value + TimeUnit.Microsecond -> AndroidTimeUnit.MICROSECONDS.toNanos(value) + TimeUnit.Millisecond -> AndroidTimeUnit.MILLISECONDS.toNanos(value) + TimeUnit.Second -> AndroidTimeUnit.SECONDS.toNanos(value) + TimeUnit.Minute -> AndroidTimeUnit.MINUTES.toNanos(value) + TimeUnit.Hour -> AndroidTimeUnit.HOURS.toNanos(value) + TimeUnit.Day -> AndroidTimeUnit.DAYS.toNanos(value) + } +} diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt index 433e4547057..7606d54cb4d 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/private/TimingDistributionMetricTypeTest.kt @@ -7,6 +7,7 @@ package mozilla.components.service.glean.private import androidx.test.core.app.ApplicationProvider import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ObsoleteCoroutinesApi +import mozilla.components.service.glean.storages.TimingDistributionData import mozilla.components.service.glean.testing.GleanTestRule import mozilla.components.service.glean.timing.TimingManager import org.junit.After @@ -164,16 +165,24 @@ class TimingDistributionMetricTypeTest { val testSamples = (1L..3L).toList().toLongArray() metric.accumulateSamples(testSamples) + val secondsToNanos = 1000L * 1000L * 1000L + // Check that data was properly recorded in the second ping. assertTrue(metric.testHasValue("store1")) val snapshot = metric.testGetValue("store1") // Check the sum - assertEquals(6L, snapshot.sum) + assertEquals(6L * secondsToNanos, snapshot.sum) // Check that the 1L fell into the first bucket - assertEquals(1L, snapshot.values[1]) + assertEquals( + 1L, snapshot.values[TimingDistributionData.sampleToBucketMinimum(1 * secondsToNanos)] + ) // Check that the 2L fell into the second bucket - assertEquals(1L, snapshot.values[2]) + assertEquals( + 1L, snapshot.values[TimingDistributionData.sampleToBucketMinimum(2 * secondsToNanos)] + ) // Check that the 3L fell into the third bucket - assertEquals(1L, snapshot.values[3]) + assertEquals( + 1L, snapshot.values[TimingDistributionData.sampleToBucketMinimum(3 * secondsToNanos)] + ) } } From 1c3f024982426b80b65ba9efc398ec27630b7940 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Aug 2019 11:52:11 -0400 Subject: [PATCH 25/38] Fix linting --- .../service/glean/storages/TimingDistributionsStorageEngine.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt index 6cc9c56ea6d..fe589e1ec86 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt @@ -81,6 +81,7 @@ internal open class TimingDistributionsStorageEngineImplementation( * @param samples the values to accumulate, in the given `timeUnit` * @param timeUnit the unit that the given samples are in, defaults to nanoseconds */ + @Suppress("ComplexMethod") @Synchronized fun accumulateSamples( metricData: CommonMetricData, @@ -241,7 +242,7 @@ data class TimingDistributionData( * @param json Stringified JSON value representing a [TimingDistributionData] object * @return A [TimingDistributionData] or null if unable to rebuild from the string. */ - @Suppress("ReturnCount", "ComplexMethod") + @Suppress("ReturnCount", "ComplexMethod", "NestedBlockDepth") internal fun fromJsonString(json: String): TimingDistributionData? { val jsonObject: JSONObject try { From 0c17e082c999d087f761e6920e71943637eb6497 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 7 Aug 2019 11:14:08 -0400 Subject: [PATCH 26/38] Update comments based on feedback in the PR --- .../service/glean/private/HistogramBase.kt | 6 ------ .../private/TimingDistributionMetricType.kt | 16 ++++++++++++++++ .../storages/TimingDistributionsStorageEngine.kt | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/HistogramBase.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/HistogramBase.kt index dc0b4439f8f..70a3d30c819 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/private/HistogramBase.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/HistogramBase.kt @@ -12,12 +12,6 @@ interface HistogramBase { /** * Accumulates the provided samples in the metric. * - * Please note that this assumes that the provided samples are already in the - * "unit" declared by the instance of the implementing metric type (e.g. if the - * implementing class is a [TimingDistributionMetricType] and the instance this - * method was called on is using [TimeUnit.Second], then `samples` are assumed - * to be in that unit). - * * @param samples the [LongArray] holding the samples to be recorded by the metric. */ fun accumulateSamples(samples: LongArray) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt index 666bdd649f9..2cef2bfef16 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt @@ -15,6 +15,13 @@ import mozilla.components.support.base.log.logger.Logger /** * This implements the developer facing API for recording timing distribution metrics. * + * The `timeUnit` parameter is only used when the values are set directly + * through `accumulateSamples`, which is used for bringing in GeckoView metrics, + * and not for normal use. + * + * To prevent the number of buckets from being unbounded, timings longer than 10 minutes + * are truncated to 10 minutes. + * * Instances of this class type are automatically generated by the parsers at build time, * allowing developers to record values that were previously registered in the metrics.yaml file. */ @@ -84,6 +91,15 @@ data class TimingDistributionMetricType( TimingManager.cancel(this, timerId) } + /** + * Accumulates the provided samples in the metric. + * + * Please note that this assumes that the provided samples are in `timeUnit` + * and will be converted to nanoseconds for storage and sending in the ping. + * + * @param samples the [LongArray] holding the samples to be recorded by the metric, in + * the unit specified by `timeUnit`. + */ override fun accumulateSamples(samples: LongArray) { if (!shouldRecord(logger)) { return diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt index fe589e1ec86..44dc9e765cc 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt @@ -36,7 +36,8 @@ internal open class TimingDistributionsStorageEngineImplementation( ) : GenericStorageEngine() { companion object { - // Maximum time of 10 minutes in nanoseconds + // Maximum time of 10 minutes in nanoseconds. This maximum means we + // retain a maximum of 313 buckets. internal const val MAX_SAMPLE_TIME: Long = 1000L * 1000L * 1000L * 60L * 10L } From a79ebfedcc7a3eba1dc0f6ce0f4172216d32d6ad Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 8 Aug 2019 14:29:27 -0400 Subject: [PATCH 27/38] Fix comment --- .../service/glean/storages/TimingDistributionsStorageEngine.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt index 44dc9e765cc..c47c535c64f 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/TimingDistributionsStorageEngine.kt @@ -16,7 +16,6 @@ import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.ktx.android.org.json.tryGetLong import mozilla.components.support.ktx.android.org.json.tryGetString import org.json.JSONObject -import java.lang.Math.log import java.lang.Math.pow import kotlin.math.log @@ -128,7 +127,7 @@ internal open class TimingDistributionsStorageEngineImplementation( logger, numTooLongSamples ) - // Too long samples should just be truncated, but otherwise we deal record and handle them + // Too long samples should just be truncated, but otherwise we record and handle them } // Since the custom combiner closure captures this value, we need to just create a dummy From bb6a3c015d2beb0c97acfdc2bafc9ec34d92af60 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 12 Aug 2019 11:44:13 -0400 Subject: [PATCH 28/38] Update hash --- components/service/glean/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/service/glean/build.gradle b/components/service/glean/build.gradle index 607623aea01..8906af30925 100644 --- a/components/service/glean/build.gradle +++ b/components/service/glean/build.gradle @@ -14,7 +14,7 @@ apply plugin: 'kotlin-android' * created during unit testing. * This uses a specific version of the schema identified by a git commit hash. */ -String GLEAN_PING_SCHEMA_GIT_HASH = "73c5a65" +String GLEAN_PING_SCHEMA_GIT_HASH = "7755497" String GLEAN_PING_SCHEMA_URL = "https://raw.githubusercontent.com/mozilla-services/mozilla-pipeline-schemas/$GLEAN_PING_SCHEMA_GIT_HASH/schemas/glean/baseline/baseline.1.schema.json" android { From 8b52b1931ef181c61e7d3f53136e815fc3d21ac0 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 12 Aug 2019 11:46:32 -0400 Subject: [PATCH 29/38] Add to changelog --- docs/changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 87a2d926395..1027cd33818 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -12,6 +12,9 @@ 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** + * Timing distributions now use a functional bucketing algorithm that does not require fixed limits to be defined up front. + * **support-test** * Fixed [#3893](https://github.com/mozilla-mobile/android-components/issues/3893) Moving WebserverRule to support-test. From 5f3be2bed403bba5d6bffc8a7b9f7dbbf62fe037 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Mon, 12 Aug 2019 10:35:13 -0400 Subject: [PATCH 30/38] Issue #3647 - Bring back siteSecurityColor --- .../browser/toolbar/BrowserToolbar.kt | 38 +++++------ .../browser/toolbar/display/DisplayToolbar.kt | 30 ++++++--- .../toolbar/display/SiteSecurityIconView.kt | 48 +++++++++++++ .../toolbar/display/SiteSecurityIcons.kt | 67 ------------------- .../res/drawable/mozac_ic_site_security.xml | 8 +++ .../main/res/values/attrs_browser_toolbar.xml | 9 ++- .../browser/toolbar/BrowserToolbarTest.kt | 19 ------ .../toolbar/display/DisplayToolbarTest.kt | 66 ++++++++++-------- .../toolbar/display/SiteSecurityIconsTest.kt | 55 --------------- .../customtabs/CustomTabsToolbarFeature.kt | 2 +- .../src/main/res/drawable/mozac_ic_lock.xml | 2 +- docs/changelog.md | 4 +- .../samples/toolbar/ToolbarActivity.kt | 4 ++ .../res/drawable/custom_security_icon.xml | 47 +++++++++++++ 14 files changed, 195 insertions(+), 204 deletions(-) create mode 100644 components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIconView.kt delete mode 100644 components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt create mode 100644 components/browser/toolbar/src/main/res/drawable/mozac_ic_site_security.xml delete mode 100644 components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/SiteSecurityIconsTest.kt create mode 100644 samples/toolbar/src/main/res/drawable/custom_security_icon.xml diff --git a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt index 0c9b3f9be0a..0fc54f11954 100644 --- a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt +++ b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt @@ -31,7 +31,6 @@ import kotlinx.coroutines.launch import mozilla.components.browser.menu.BrowserMenuBuilder import mozilla.components.browser.toolbar.display.DisplayToolbar import mozilla.components.browser.toolbar.display.DisplayToolbar.Companion.BOTTOM_PROGRESS_BAR -import mozilla.components.browser.toolbar.display.SiteSecurityIcons import mozilla.components.browser.toolbar.display.TrackingProtectionIconView import mozilla.components.browser.toolbar.edit.EditToolbar import mozilla.components.concept.toolbar.AutocompleteDelegate @@ -114,12 +113,21 @@ class BrowserToolbar @JvmOverloads constructor( } /** - * Set/Get the site security icons (usually a lock or globe icon). It uses a pair of drawables - * which represent the insecure and secure colours respectively. + * Set/Get the site security icon (usually a lock and globe icon). It uses a + * [android.graphics.drawable.StateListDrawable] where "state_site_secure" represents the secure + * icon and empty state represents the insecure icon. */ - var siteSecurityIcons - get() = displayToolbar.securityIcons - set(value) { displayToolbar.securityIcons = value } + var siteSecurityIcon + get() = displayToolbar.securityIcon + set(value) { displayToolbar.securityIcon = value } + + /** + * Set/Get the site security icon colours. It uses a pair of color integers + * which represent the insecure and secure colours respectively. + */ + var siteSecurityColor: Pair + get() = displayToolbar.securityIconColor + set(value) { displayToolbar.securityIconColor = value } /** * Gets/Sets a custom view that will be drawn as behind the URL and page actions in display mode. @@ -301,11 +309,6 @@ class BrowserToolbar @JvmOverloads constructor( editToolbar.urlView.typeface = value } - fun setSiteSecurityColor(colors: Pair) { - displayToolbar.securityIcons = - displayToolbar.securityIcons.withColorFilter(colors.first, colors.second) - } - /** * Sets a listener to be invoked when focus of the URL input view (in edit mode) changed. */ @@ -474,20 +477,17 @@ class BrowserToolbar @JvmOverloads constructor( R.styleable.BrowserToolbar_browserToolbarSuggestionBackgroundColor, suggestionBackgroundColor ) - val inSecureIcon = getDrawable(R.styleable.BrowserToolbar_browserToolbarInsecureIcon) - ?: displayToolbar.securityIcons.insecure - val secureIcon = getDrawable(R.styleable.BrowserToolbar_browserToolbarSecureIcon) - ?: displayToolbar.securityIcons.secure - val inSecureColor = getColor( + siteSecurityIcon = getDrawable(R.styleable.BrowserToolbar_browserToolbarSecurityIcon) + ?: displayToolbar.securityIcon + val insecureColor = getColor( R.styleable.BrowserToolbar_browserToolbarInsecureColor, displayToolbar.defaultColor ) val secureColor = getColor( - R.styleable.BrowserToolbar_browserToolbarSecureColor, + R.styleable.BrowserToolbar_browserToolbarInsecureColor, displayToolbar.defaultColor ) - siteSecurityIcons = SiteSecurityIcons(inSecureIcon, secureIcon) - .withColorFilter(inSecureColor, secureColor) + siteSecurityColor = insecureColor to secureColor val fadingEdgeLength = getDimensionPixelSize( R.styleable.BrowserToolbar_browserToolbarFadingEdgeSize, resources.getDimensionPixelSize(R.dimen.mozac_browser_toolbar_url_fading_edge_size) diff --git a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt index 278b995f380..5509fea3895 100644 --- a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt +++ b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt @@ -6,6 +6,7 @@ package mozilla.components.browser.toolbar.display import android.annotation.SuppressLint import android.content.Context +import android.graphics.Color import android.graphics.drawable.Drawable import android.view.Gravity import android.view.View @@ -29,10 +30,10 @@ import mozilla.components.browser.toolbar.internal.wrapAction import mozilla.components.concept.toolbar.Toolbar import mozilla.components.concept.toolbar.Toolbar.SiteSecurity import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection +import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection.OFF_FOR_A_SITE +import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection.OFF_GLOBALLY import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection.ON_NO_TRACKERS_BLOCKED import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection.ON_TRACKERS_BLOCKED -import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection.OFF_GLOBALLY -import mozilla.components.concept.toolbar.Toolbar.SiteTrackingProtection.OFF_FOR_A_SITE /** * Sub-component of the browser toolbar responsible for displaying the URL and related controls. @@ -127,7 +128,13 @@ internal class DisplayToolbar( private var siteTrackingProtection = OFF_GLOBALLY - internal var securityIcons = SiteSecurityIcons.getDefaultSecurityIcons(context, defaultColor) + internal var securityIcon = context.getDrawable(R.drawable.mozac_ic_site_security) + set(value) { + field = value + siteSecurityIconView.setImageDrawable(value) + } + + internal var securityIconColor = defaultColor to defaultColor set(value) { field = value setSiteSecurity(currentSiteSecurity) @@ -160,11 +167,9 @@ internal class DisplayToolbar( setOnClickListener(null) } - internal val siteSecurityIconView = AppCompatImageView(context).apply { + internal val siteSecurityIconView = SiteSecurityIconView(context).apply { setPadding(resources.getDimensionPixelSize(R.dimen.mozac_browser_toolbar_icon_padding)) - setImageDrawable(securityIcons.insecure) - // Avoiding text behind the icon being selectable. If the listener is not set // with a value or null text behind the icon can be selectable. // https://github.com/mozilla-mobile/reference-browser/issues/448 @@ -305,12 +310,17 @@ internal class DisplayToolbar( * Sets the site's security icon as secure if true, else the regular globe. */ fun setSiteSecurity(secure: SiteSecurity) { - val drawable = when (secure) { - SiteSecurity.INSECURE -> securityIcons.insecure - SiteSecurity.SECURE -> securityIcons.secure + @ColorInt val color = when (secure) { + SiteSecurity.INSECURE -> securityIconColor.first + SiteSecurity.SECURE -> securityIconColor.second + } + if (color == Color.TRANSPARENT) { + siteSecurityIconView.clearColorFilter() + } else { + siteSecurityIconView.setColorFilter(color) } - siteSecurityIconView.setImageDrawable(drawable) + siteSecurityIconView.siteSecurity = secure currentSiteSecurity = secure } diff --git a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIconView.kt b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIconView.kt new file mode 100644 index 00000000000..4821b3306ca --- /dev/null +++ b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIconView.kt @@ -0,0 +1,48 @@ +/* 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 mozilla.components.browser.toolbar.display + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import androidx.appcompat.widget.AppCompatImageView +import mozilla.components.browser.toolbar.R +import mozilla.components.concept.toolbar.Toolbar.SiteSecurity + +/** + * Internal widget to display the different icons of site security, relies on the + * [SiteSecurity] state of each page. + */ +internal class SiteSecurityIconView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : AppCompatImageView(context, attrs, defStyleAttr) { + + // We allow null here because in some situations, onCreateDrawableState is getting called from + // the super() constructor on the View class, way before this class properties get + // initialized causing a null pointer exception. + // See for more details: https://github.com/mozilla-mobile/android-components/issues/4058 + var siteSecurity: SiteSecurity? = SiteSecurity.INSECURE + set(value) { + if (value != field) { + field = value + refreshDrawableState() + } + + field = value + } + + override fun onCreateDrawableState(extraSpace: Int): IntArray { + return when (siteSecurity) { + SiteSecurity.INSECURE, null -> super.onCreateDrawableState(extraSpace) + SiteSecurity.SECURE -> { + val drawableState = super.onCreateDrawableState(extraSpace + 1) + View.mergeDrawableStates(drawableState, intArrayOf(R.attr.state_site_secure)) + drawableState + } + } + } +} diff --git a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt b/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt deleted file mode 100644 index 7b0434d6bab..00000000000 --- a/components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIcons.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* 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 mozilla.components.browser.toolbar.display - -import android.content.Context -import android.graphics.BlendMode -import android.graphics.BlendModeColorFilter -import android.graphics.ColorFilter -import android.graphics.PorterDuff -import android.graphics.PorterDuffColorFilter -import android.graphics.drawable.Drawable -import android.os.Build -import android.os.Build.VERSION.SDK_INT -import androidx.annotation.ColorInt -import mozilla.components.ui.icons.R - -/** - * Specifies icons to display in the toolbar representing the security of the current website. - * - * @property insecure Icon to display for HTTP sites. - * @property secure Icon to display for HTTPS sites. - */ -data class SiteSecurityIcons( - val insecure: Drawable?, - val secure: Drawable? -) { - - /** - * Returns an instance of [SiteSecurityIcons] with a color filter applied to each icon. - */ - fun withColorFilter(insecureColorFilter: ColorFilter, secureColorFilter: ColorFilter): SiteSecurityIcons { - return copy( - insecure = insecure?.apply { colorFilter = insecureColorFilter }, - secure = secure?.apply { colorFilter = secureColorFilter } - ) - } - - /** - * Returns an instance of [SiteSecurityIcons] with a color tint applied to each icon. - */ - fun withColorFilter(@ColorInt insecureColor: Int, @ColorInt secureColor: Int): SiteSecurityIcons { - val insecureColorFilter: ColorFilter = if (SDK_INT >= Build.VERSION_CODES.Q) { - BlendModeColorFilter(insecureColor, BlendMode.SRC_IN) - } else { - PorterDuffColorFilter(insecureColor, PorterDuff.Mode.SRC_IN) - } - - val secureColorFilter: ColorFilter = if (SDK_INT >= Build.VERSION_CODES.Q) { - BlendModeColorFilter(secureColor, BlendMode.SRC_IN) - } else { - PorterDuffColorFilter(secureColor, PorterDuff.Mode.SRC_IN) - } - - return withColorFilter(insecureColorFilter, secureColorFilter) - } - - companion object { - fun getDefaultSecurityIcons(context: Context, @ColorInt color: Int): SiteSecurityIcons { - return SiteSecurityIcons( - insecure = context.getDrawable(R.drawable.mozac_ic_globe), - secure = context.getDrawable(R.drawable.mozac_ic_lock) - ).withColorFilter(color, color) - } - } -} diff --git a/components/browser/toolbar/src/main/res/drawable/mozac_ic_site_security.xml b/components/browser/toolbar/src/main/res/drawable/mozac_ic_site_security.xml new file mode 100644 index 00000000000..cdba3bc2eab --- /dev/null +++ b/components/browser/toolbar/src/main/res/drawable/mozac_ic_site_security.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/components/browser/toolbar/src/main/res/values/attrs_browser_toolbar.xml b/components/browser/toolbar/src/main/res/values/attrs_browser_toolbar.xml index eef30845fda..d2a78de9e58 100644 --- a/components/browser/toolbar/src/main/res/values/attrs_browser_toolbar.xml +++ b/components/browser/toolbar/src/main/res/values/attrs_browser_toolbar.xml @@ -8,10 +8,9 @@ - - - + + @@ -29,4 +28,8 @@ + + + +
    diff --git a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/BrowserToolbarTest.kt b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/BrowserToolbarTest.kt index 1f309a72662..600718a60a6 100644 --- a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/BrowserToolbarTest.kt +++ b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/BrowserToolbarTest.kt @@ -6,8 +6,6 @@ package mozilla.components.browser.toolbar import android.content.Context import android.graphics.Color -import android.graphics.PorterDuff -import android.graphics.PorterDuffColorFilter import android.graphics.Typeface import android.graphics.drawable.Drawable import android.util.AttributeSet @@ -908,23 +906,6 @@ class BrowserToolbarTest { assertEquals(View.VISIBLE, toolbar.displayToolbar.siteSecurityIconView.visibility) } - @Test - fun `siteSecurityColor setter`() { - val toolbar = BrowserToolbar(testContext) - - toolbar.setSiteSecurityColor(Color.RED to Color.BLUE) - assertEquals( - PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN), - toolbar.displayToolbar.siteSecurityIconView.drawable.colorFilter - ) - - toolbar.siteSecure = SiteSecurity.SECURE - assertEquals( - PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN), - toolbar.displayToolbar.siteSecurityIconView.drawable.colorFilter - ) - } - @Test fun `urlBoxView getter`() { val toolbar = BrowserToolbar(testContext) diff --git a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/DisplayToolbarTest.kt b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/DisplayToolbarTest.kt index abc4939c653..6d8789cc4e5 100644 --- a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/DisplayToolbarTest.kt +++ b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/DisplayToolbarTest.kt @@ -4,7 +4,9 @@ package mozilla.components.browser.toolbar.display +import android.graphics.Color import android.graphics.Rect +import android.graphics.drawable.Drawable import android.view.View import android.view.ViewGroup import android.widget.ImageButton @@ -42,19 +44,10 @@ import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.spy import org.mockito.Mockito.verify -import org.robolectric.Shadows.shadowOf @RunWith(AndroidJUnit4::class) class DisplayToolbarTest { - @Test - fun `initialized with security icon`() { - val toolbar = mock(BrowserToolbar::class.java) - val displayToolbar = DisplayToolbar(testContext, toolbar) - - assertNotNull(displayToolbar.siteSecurityIconView.drawable) - } - @Test fun `clicking on the URL switches the toolbar to editing mode`() { val toolbar = mock(BrowserToolbar::class.java) @@ -960,45 +953,64 @@ class DisplayToolbarTest { } @Test - fun `iconView changes image resource when site security changes`() { + fun `iconView changes site secure state when site security changes`() { val toolbar = mock(BrowserToolbar::class.java) val displayToolbar = DisplayToolbar(testContext, toolbar) - var shadowDrawable = shadowOf(displayToolbar.siteSecurityIconView.drawable) - assertEquals(R.drawable.mozac_ic_globe, shadowDrawable.createdFromResId) + assertEquals(SiteSecurity.INSECURE, displayToolbar.siteSecurityIconView.siteSecurity) displayToolbar.setSiteSecurity(SiteSecurity.SECURE) - shadowDrawable = shadowOf(displayToolbar.siteSecurityIconView.drawable) - assertEquals(R.drawable.mozac_ic_lock, shadowDrawable.createdFromResId) + assertEquals(SiteSecurity.SECURE, displayToolbar.siteSecurityIconView.siteSecurity) displayToolbar.setSiteSecurity(SiteSecurity.INSECURE) - shadowDrawable = shadowOf(displayToolbar.siteSecurityIconView.drawable) - assertEquals(R.drawable.mozac_ic_globe, shadowDrawable.createdFromResId) + assertEquals(SiteSecurity.INSECURE, displayToolbar.siteSecurityIconView.siteSecurity) } @Test - fun `securityIcons is set when securityIcons changes`() { + fun `securityIcon is set when securityIcon changes`() { val toolbar = mock(BrowserToolbar::class.java) val displayToolbar = DisplayToolbar(testContext, toolbar) - val insecure = testContext.getDrawable(R.drawable.mozac_ic_globe) - val secure = testContext.getDrawable(R.drawable.mozac_ic_lock) - displayToolbar.securityIcons = SiteSecurityIcons(insecure, secure) + val icon = testContext.getDrawable(R.drawable.mozac_ic_site_security) + displayToolbar.securityIcon = icon + + assertEquals(icon, displayToolbar.securityIcon) + } + + @Test + fun `setImageDrawable is called when securityIcon changes`() { + val toolbar = BrowserToolbar(testContext) + + val icon: Drawable = mock() + assertNotEquals(icon, toolbar.displayToolbar.siteSecurityIconView.drawable) + + toolbar.siteSecurityIcon = icon + assertEquals(icon, toolbar.displayToolbar.siteSecurityIconView.drawable) + } + + @Test + fun `securityIconColor is set when securityIconColor changes`() { + val toolbar = BrowserToolbar(testContext) + + assertNull(toolbar.displayToolbar.siteSecurityIconView.colorFilter) + + toolbar.siteSecurityColor = Color.TRANSPARENT to Color.TRANSPARENT + assertNull(toolbar.displayToolbar.siteSecurityIconView.colorFilter) - assertEquals(insecure, displayToolbar.securityIcons.insecure) - assertEquals(secure, displayToolbar.securityIcons.secure) + toolbar.siteSecurityColor = Color.BLUE to Color.BLUE + assertNotNull(toolbar.displayToolbar.siteSecurityIconView.colorFilter) } @Test - fun `setSiteSecurity is called when securityIcons changes`() { + fun `setSiteSecurity is called when securityIconColor changes`() { val toolbar = BrowserToolbar(testContext) - val icons = SiteSecurityIcons(mock(), mock()) - assertNotEquals(icons, toolbar.displayToolbar.securityIcons) + val icon: Drawable = mock() + assertNotEquals(icon, toolbar.displayToolbar.securityIcon) - toolbar.siteSecurityIcons = icons - assertEquals(icons, toolbar.displayToolbar.securityIcons) + toolbar.siteSecurityIcon = icon + assertEquals(icon, toolbar.displayToolbar.securityIcon) } @Test diff --git a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/SiteSecurityIconsTest.kt b/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/SiteSecurityIconsTest.kt deleted file mode 100644 index cd6a7596999..00000000000 --- a/components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/SiteSecurityIconsTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* 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 mozilla.components.browser.toolbar.display - -import android.graphics.Color -import android.graphics.ColorMatrix -import android.graphics.ColorMatrixColorFilter -import android.graphics.PorterDuff -import android.graphics.PorterDuffColorFilter -import android.graphics.drawable.Drawable -import androidx.test.ext.junit.runners.AndroidJUnit4 -import mozilla.components.support.test.mock -import mozilla.components.support.test.robolectric.testContext -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.verify - -@RunWith(AndroidJUnit4::class) -class SiteSecurityIconsTest { - - @Test - fun `default returns non-null tinted icons`() { - val icons = SiteSecurityIcons.getDefaultSecurityIcons(testContext, Color.RED) - assertEquals(PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN), icons.insecure?.colorFilter) - assertEquals(PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN), icons.secure?.colorFilter) - } - - @Test - fun `withColorFilter tints existing drawables`() { - val insecure: Drawable = mock() - val secure: Drawable = mock() - val icons = SiteSecurityIcons(insecure, secure).withColorFilter(Color.BLUE, Color.RED) - - assertEquals(insecure, icons.insecure) - assertEquals(secure, icons.secure) - verify(insecure).colorFilter = PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) - verify(secure).colorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN) - } - - @Test - fun `withColorFilter allows custom filters to be used`() { - val insecure: Drawable = mock() - val secure: Drawable = mock() - val filter = ColorMatrixColorFilter(ColorMatrix()) - val icons = SiteSecurityIcons(insecure, secure).withColorFilter(filter, filter) - - assertEquals(insecure, icons.insecure) - assertEquals(secure, icons.secure) - verify(insecure).colorFilter = filter - verify(secure).colorFilter = filter - } -} diff --git a/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabsToolbarFeature.kt b/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabsToolbarFeature.kt index 055663d9f0d..705a139ae9e 100644 --- a/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabsToolbarFeature.kt +++ b/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabsToolbarFeature.kt @@ -101,7 +101,7 @@ class CustomTabsToolbarFeature( toolbar.setBackgroundColor(color) toolbar.textColor = readableColor toolbar.titleColor = readableColor - toolbar.setSiteSecurityColor(readableColor to readableColor) + toolbar.siteSecurityColor = readableColor to readableColor toolbar.menuViewColor = readableColor window?.setStatusBarTheme(color) diff --git a/components/ui/icons/src/main/res/drawable/mozac_ic_lock.xml b/components/ui/icons/src/main/res/drawable/mozac_ic_lock.xml index 2d77e7b3391..77d7c6b01a1 100644 --- a/components/ui/icons/src/main/res/drawable/mozac_ic_lock.xml +++ b/components/ui/icons/src/main/res/drawable/mozac_ic_lock.xml @@ -9,5 +9,5 @@ android:viewportHeight="24.0"> + android:pathData="M17 11V8A5 5 0 0 0 7 8v3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zM9 8a3 3 0 0 1 3-3 3 3 0 0 1 3 3v3H9z"/> diff --git a/docs/changelog.md b/docs/changelog.md index 1027cd33818..d555f147e48 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -22,8 +22,8 @@ permalink: /changelog/ * The component now handles situations where the Android system kills the content process (without killing the main app process) in order to reclaim resources. In those situations the component will automatically recover and restore the last known state of those sessions. * **browser-toolbar** - * ⚠️ **This is a breaking change**: The `BrowserToolbar.siteSecurityColor` property has been replaced with the setter `BrowserToolbar.setSiteSecurityColor`. - * Added `BrowserToolbar.siteSecurityIcons` to use custom security icons with multiple colors in the toolbar. + * Changed `BrowserToolbar.siteSecurityColor` to use no icon color filter when the color is set to `Color.TRANSPARENT`. + * Added `BrowserToolbar.siteSecurityIcon` to use custom security icons with multiple colors in the toolbar. * **feature-sendtab** * Added a `SendTabFeature` that observes account device events with optional support for push notifications. diff --git a/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt b/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt index 59ed69d8fdd..1d26f4d94f0 100644 --- a/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt +++ b/samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt @@ -5,6 +5,7 @@ package org.mozilla.samples.toolbar import android.content.res.Resources +import android.graphics.Color import android.os.Bundle import android.view.View import androidx.annotation.DrawableRes @@ -160,6 +161,9 @@ class ToolbarActivity : AppCompatActivity() { */ private fun setupCustomMenu() { + toolbar.siteSecurityColor = Color.TRANSPARENT to Color.TRANSPARENT + toolbar.siteSecurityIcon = getDrawable(R.drawable.custom_security_icon) + toolbar.setBackgroundColor( ContextCompat.getColor(this, mozilla.components.ui.colors.R.color.photonBlue80)) diff --git a/samples/toolbar/src/main/res/drawable/custom_security_icon.xml b/samples/toolbar/src/main/res/drawable/custom_security_icon.xml new file mode 100644 index 00000000000..d0b622e9921 --- /dev/null +++ b/samples/toolbar/src/main/res/drawable/custom_security_icon.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 08523f9f5a62dd1c5eb202a1f18d36ba0c0c14c9 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Aug 2019 17:29:26 -0400 Subject: [PATCH 31/38] 1571744: Add custom distribution metric type --- .../private/CustomDistributionMetricType.kt | 88 +++ .../CustomDistributionsStorageEngine.kt | 384 +++++++++++++ .../glean/storages/StorageEngineManager.kt | 3 + .../CustomDistributionMetricTypeTest.kt | 171 ++++++ .../CustomDistributionsStorageEngineTest.kt | 512 ++++++++++++++++++ 5 files changed, 1158 insertions(+) create mode 100644 components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt create mode 100644 components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt create mode 100644 components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt create mode 100644 components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt new file mode 100644 index 00000000000..79651654f72 --- /dev/null +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt @@ -0,0 +1,88 @@ +/* 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 mozilla.components.service.glean.private + +import androidx.annotation.VisibleForTesting +import mozilla.components.service.glean.Dispatchers +import mozilla.components.service.glean.storages.CustomDistributionData +import mozilla.components.service.glean.storages.CustomDistributionsStorageEngine +import mozilla.components.support.base.log.logger.Logger + +/** + * This implements the developer facing API for recording custom distribution metrics. + * + * Instances of this class type are automatically generated by the parsers at build time, + * allowing developers to record values that were previously registered in the metrics.yaml file. + */ +data class CustomDistributionMetricType( + override val disabled: Boolean, + override val category: String, + override val lifetime: Lifetime, + override val name: String, + override val sendInPings: List, + val range: List, + val bucketCount: Int, + val histogramType: HistogramType +) : CommonMetricData, HistogramBase { + init { + assert(range.size == 2) + } + + private val logger = Logger("glean/CustomDistributionMetricType") + + override fun accumulateSamples(samples: LongArray) { + if (!shouldRecord(logger)) { + return + } + + @Suppress("EXPERIMENTAL_API_USAGE") + Dispatchers.API.launch { + CustomDistributionsStorageEngine.accumulateSamples( + metricData = this@CustomDistributionMetricType, + samples = samples, + rangeMin = range[0], + rangeMax = range[1], + bucketCount = bucketCount, + histogramType = histogramType + ) + } + } + + /** + * Tests whether a value is stored for the metric for testing purposes only. This function will + * attempt to await the last task (if any) writing to the the metric's storage engine before + * returning a value. + * + * @param pingName represents the name of the ping to retrieve the metric for. Defaults + * to the either the first value in [defaultStorageDestinations] or the first + * value in [sendInPings] + * @return true if metric value exists, otherwise false + */ + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + fun testHasValue(pingName: String = sendInPings.first()): Boolean { + @Suppress("EXPERIMENTAL_API_USAGE") + Dispatchers.API.assertInTestingMode() + + return CustomDistributionsStorageEngine.getSnapshot(pingName, false)?.get(identifier) != null + } + + /** + * Returns the stored value for testing purposes only. This function will attempt to await the + * last task (if any) writing to the the metric's storage engine before returning a value. + * + * @param pingName represents the name of the ping to retrieve the metric for. Defaults + * to the either the first value in [defaultStorageDestinations] or the first + * value in [sendInPings] + * @return value of the stored metric + * @throws [NullPointerException] if no value is stored + */ + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + fun testGetValue(pingName: String = sendInPings.first()): CustomDistributionData { + @Suppress("EXPERIMENTAL_API_USAGE") + Dispatchers.API.assertInTestingMode() + + return CustomDistributionsStorageEngine.getSnapshot(pingName, false)!![identifier]!! + } +} diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt new file mode 100644 index 00000000000..bd9cf1a382c --- /dev/null +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt @@ -0,0 +1,384 @@ +/* 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 mozilla.components.service.glean.storages + +import android.annotation.SuppressLint +import android.content.SharedPreferences +import androidx.annotation.VisibleForTesting +import mozilla.components.service.glean.error.ErrorRecording +import mozilla.components.service.glean.private.CommonMetricData +import mozilla.components.service.glean.private.HistogramType + +import mozilla.components.support.base.log.logger.Logger +import mozilla.components.support.ktx.android.org.json.tryGetInt +import mozilla.components.support.ktx.android.org.json.tryGetLong +import mozilla.components.support.ktx.android.org.json.tryGetString +import org.json.JSONArray +import org.json.JSONObject + +/** + * This singleton handles the in-memory storage logic for timing distributions. It is meant to be + * used by the Timing Distribution API and the ping assembling objects. + * + * This class contains a reference to the Android application Context. While the IDE warns + * us that this could leak, the application context lives as long as the application and this + * object. For this reason, we should be safe to suppress the IDE warning. + */ +@SuppressLint("StaticFieldLeak") +internal object CustomDistributionsStorageEngine : CustomDistributionsStorageEngineImplementation() + +internal open class CustomDistributionsStorageEngineImplementation( + override val logger: Logger = Logger("glean/CustomDistributionsStorageEngine") +) : GenericStorageEngine() { + + override fun deserializeSingleMetric(metricName: String, value: Any?): CustomDistributionData? { + return try { + (value as? String)?.let { + CustomDistributionData.fromJsonString(it) + } + } catch (e: org.json.JSONException) { + null + } + } + + override fun serializeSingleMetric( + userPreferences: SharedPreferences.Editor?, + storeName: String, + value: CustomDistributionData, + extraSerializationData: Any? + ) { + val json = value.toJsonObject() + userPreferences?.putString(storeName, json.toString()) + } + + /** + * Accumulate an array of samples for the provided metric. + * + * @param metricData the metric information for the custom distribution + * @param samples the values to accumulate + */ + @Suppress("LongParameterList") + @Synchronized + fun accumulateSamples( + metricData: CommonMetricData, + samples: LongArray, + rangeMin: Long, + rangeMax: Long, + bucketCount: Int, + histogramType: HistogramType + ) { + val validSamples = samples.filter { sample -> sample >= 0 } + val numNegativeSamples = samples.size - validSamples.size + if (numNegativeSamples > 0) { + ErrorRecording.recordError( + metricData, + ErrorRecording.ErrorType.InvalidValue, + "Accumulate $numNegativeSamples negative samples", + logger, + numNegativeSamples + ) + return + } + + // Since the custom combiner closure captures this value, we need to just create a dummy + // value here that won't be used by the combine function, and create a fresh + // CustomDistributionData for each value that doesn't have an existing current value. + val dummy = CustomDistributionData( + category = metricData.category, + name = metricData.name, + rangeMin = rangeMin, + rangeMax = rangeMax, + bucketCount = bucketCount, + histogramType = histogramType + ) + validSamples.forEach { sample -> + super.recordMetric(metricData, dummy, null) { currentValue, _ -> + currentValue?.let { + it.accumulate(sample) + it + } ?: let { + val newTD = CustomDistributionData( + category = metricData.category, + name = metricData.name, + rangeMin = rangeMin, + rangeMax = rangeMax, + bucketCount = bucketCount, + histogramType = histogramType + ) + newTD.accumulate(sample) + return@let newTD + } + } + } + } + + /** + * Get a snapshot of the stored data as a JSON object. + * + * @param storeName the name of the desired store + * @param clearStore whether or not to clearStore the requested store + * + * @return the [JSONObject] containing the recorded data. + */ + override fun getSnapshotAsJSON(storeName: String, clearStore: Boolean): Any? { + return getSnapshot(storeName, clearStore)?.let { dataMap -> + val jsonObj = JSONObject() + dataMap.forEach { + jsonObj.put(it.key, it.value.toJsonObject()) + } + return jsonObj + } + } +} + +/** + * This class represents the structure of a custom distribution according to the pipeline schema. It + * is meant to help serialize and deserialize data to the correct format for transport and storage, + * as well as including a helper function to calculate the bucket sizes. + * + * @param category of the metric + * @param name of the metric + * @param bucketCount total number of buckets + * @param rangeMin the minimum value that can be represented + * @param rangeMax the maximum value that can be represented + * @param histogramType the [HistogramType] representing the bucket layout + * @param values a map containing the bucket index mapped to the accumulated count + * @param sum the accumulated sum of all the samples in the timing distribution + */ +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +data class CustomDistributionData( + val category: String, + val name: String, + val rangeMin: Long, + val rangeMax: Long, + val bucketCount: Int, + val histogramType: HistogramType, + // map from bucket limits to accumulated values + val values: MutableMap = mutableMapOf(), + var sum: Long = 0 +) { + companion object { + /** + * Factory function that takes stringified JSON and converts it back into a + * [CustomHistogramData]. This tries to read all values and attempts to + * use a default where no value exists. + * + * @param json Stringified JSON value representing a [CustomDistributionData] object + * @return A [CustomDistributionData] or null if unable to rebuild from the string. + */ + @Suppress("ReturnCount", "ComplexMethod") + internal fun fromJsonString(json: String): CustomDistributionData? { + val jsonObject: JSONObject + try { + jsonObject = JSONObject(json) + } catch (e: org.json.JSONException) { + return null + } + + // Category can be empty so it may be possible to be a null value so try and allow this + // by using `orEmpty()` to fill in the value. Other values should be present or else + // something is wrong and we should return null. + val category = jsonObject.tryGetString("category").orEmpty() + val name = jsonObject.tryGetString("name") ?: return null + val bucketCount = jsonObject.tryGetInt("bucket_count") ?: return null + // If 'range' isn't present, JSONException is thrown + val range = try { + val array = jsonObject.getJSONArray("range") + // Range must have exactly 2 values + if (array.length() == 2) { + // The getLong() function throws JSONException if we can't convert to a Long, so + // the catch should return null if either value isn't a valid Long + array.getLong(0) + array.getLong(1) + // This returns the JSONArray to the assignment if everything checks out + array + } else { + return null + } + } catch (e: org.json.JSONException) { + return null + } + val rawHistogramType = jsonObject.tryGetString("histogram_type") ?: return null + val histogramType = try { + HistogramType.valueOf(rawHistogramType.capitalize()) + } catch (e: IllegalArgumentException) { + return null + } + // Attempt to parse the values map, if it fails then something is wrong and we need to + // return null. + val values = try { + val mapData = jsonObject.getJSONObject("values") + val valueMap: MutableMap = mutableMapOf() + mapData.keys().forEach { key -> + valueMap[key.toLong()] = mapData.tryGetLong(key) ?: 0L + } + valueMap + } catch (e: org.json.JSONException) { + // This should only occur if there isn't a key/value pair stored for "values" + return null + } + val sum = jsonObject.tryGetLong("sum") ?: return null + + return CustomDistributionData( + category = category, + name = name, + bucketCount = bucketCount, + rangeMin = range.getLong(0), + rangeMax = range.getLong(1), + histogramType = histogramType, + values = values, + sum = sum + ) + } + } + + // This is a calculated read-only property that returns the total count of accumulated values + val count: Long + get() = values.map { it.value }.sum() + + // This is a helper property to build the correct identifier for the metric and allow for + // blank categories + internal val identifier: String = if (category.isEmpty()) { name } else { "$category.$name" } + + // This is a list of limits for the buckets. Instantiated lazily to ensure that the range and + // bucket counts are set first. + internal val buckets: List by lazy { getBuckets() } + + /** + * Finds the correct bucket, using a binary search to locate the index of the + * bucket where the sample is bigger than or equal to the bucket limit. + * + * @param sample Long value representing the sample that is being accumulated + */ + internal fun findBucket(sample: Long): Long { + var under = 0 + var over = bucketCount + var mid: Int + + do { + mid = under + (over - under) / 2 + if (mid == under) { + break + } + + if (buckets[mid] <= sample) { + under = mid + } else { + over = mid + } + } while (true) + + return buckets[mid] + } + + /** + * Accumulates a sample to the correct bucket. + * If a value doesn't exist for this bucket yet, one is created. + * + * @param sample Long value representing the sample that is being accumulated + */ + internal fun accumulate(sample: Long) { + val limit = findBucket(sample) + values[limit] = (values[limit] ?: 0) + 1 + sum += sample + } + + /** + * Helper function to build the [CustomDistributionData] into a JSONObject for serialization + * purposes. + */ + internal fun toJsonObject(): JSONObject { + return JSONObject(mapOf( + "category" to category, + "name" to name, + "bucket_count" to bucketCount, + "range" to JSONArray(arrayOf(rangeMin, rangeMax)), + "histogram_type" to histogramType.toString().toLowerCase(), + "values" to values.mapKeys { "${it.key}" }, + "sum" to sum + )) + } + + /** + * Helper function to generate the list of linear bucket min values used when accumulating + * to the correct buckets. + * + * @return List containing the bucket limits + */ + @Suppress("MagicNumber") + private fun getBucketsLinear(): List { + // Written to match the bucket generation on legacy desktop telemetry: + // https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py#65 + + val result: MutableList = mutableListOf() + result.add(0) + + val dmin = rangeMin.toDouble() + val dmax = rangeMax.toDouble() + + for (i in (1 until bucketCount)) { + val linearRange = (dmin * (bucketCount - 1 - i) + dmax * (i - 1)) / (bucketCount - 2) + result.add((linearRange + 0.5).toLong()) + } + + return result + } + + /** + * Helper function to generate the list of exponential bucket min values used when accumulating + * to the correct buckets. + * + * @return List containing the bucket limits + */ + private fun getBucketsExponential(): List { + // Written to match the bucket generation on legacy desktop telemetry: + // https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py#75 + + // This algorithm calculates the bucket sizes using a natural log approach to get + // `bucketCount` number of buckets, exponentially spaced between `range[MIN]` and + // `range[MAX]`. + // + // Bucket limits are the minimal bucket value. + // That means values in a bucket `i` are `range[i] <= value < range[i+1]`. + // It will always contain an underflow bucket (`< 1`). + val logMax = Math.log(rangeMax.toDouble()) + val result: MutableList = mutableListOf() + var current = rangeMin + if (current == 0L) { + current = 1L + } + + // underflow bucket + result.add(0) + result.add(current) + + for (i in 2 until bucketCount) { + val logCurrent = Math.log(current.toDouble()) + val logRatio = (logMax - logCurrent) / (bucketCount - i) + val logNext = logCurrent + logRatio + val nextValue = Math.round(Math.exp(logNext)) + if (nextValue > current) { + current = nextValue + } else { + ++current + } + result.add(current) + } + return result.sorted() + } + + /** + * Helper function to generate the list of bucket min values used when accumulating + * to the correct buckets. + * + * @return List containing the bucket limits + */ + private fun getBuckets(): List { + return when (histogramType) { + HistogramType.Linear -> getBucketsLinear() + HistogramType.Exponential -> getBucketsExponential() + } + } +} diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/StorageEngineManager.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/StorageEngineManager.kt index 8128e2fa172..42f2fe4931b 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/StorageEngineManager.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/StorageEngineManager.kt @@ -7,6 +7,7 @@ package mozilla.components.service.glean.storages import android.content.Context import mozilla.components.service.glean.private.BooleanMetricType import mozilla.components.service.glean.private.CounterMetricType +import mozilla.components.service.glean.private.CustomDistributionMetricType import mozilla.components.service.glean.private.DatetimeMetricType import mozilla.components.service.glean.private.StringListMetricType import mozilla.components.service.glean.private.StringMetricType @@ -26,6 +27,7 @@ internal class StorageEngineManager( private val storageEngines: Map = mapOf( "boolean" to BooleansStorageEngine, "counter" to CountersStorageEngine, + "custom_distribution" to CustomDistributionsStorageEngine, "datetime" to DatetimesStorageEngine, "events" to EventsStorageEngine, "string" to StringsStorageEngine, @@ -143,6 +145,7 @@ internal class StorageEngineManager( return when (subMetric) { is BooleanMetricType -> BooleansStorageEngine is CounterMetricType -> CountersStorageEngine + is CustomDistributionMetricType -> CustomDistributionsStorageEngine is DatetimeMetricType -> DatetimesStorageEngine is StringListMetricType -> StringListsStorageEngine is StringMetricType -> StringsStorageEngine diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt new file mode 100644 index 00000000000..cf4f5a247d3 --- /dev/null +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt @@ -0,0 +1,171 @@ +/* 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 mozilla.components.service.glean.private + +import androidx.test.core.app.ApplicationProvider +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.ObsoleteCoroutinesApi +import mozilla.components.service.glean.testing.GleanTestRule +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.assertFalse +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import java.lang.NullPointerException + +@ObsoleteCoroutinesApi +@ExperimentalCoroutinesApi +@RunWith(RobolectricTestRunner::class) +class CustomDistributionMetricTypeTest { + + @get:Rule + val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) + + @Test + fun `The API saves to its storage engine`() { + // Define a custom distribution metric which will be stored in "store1" + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Accumulate a few values + for (i in 1L..3L) { + metric.accumulateSamples(listOf(i).toLongArray()) + } + + // Check that data was properly recorded. + assertTrue(metric.testHasValue()) + val snapshot = metric.testGetValue() + // Check the sum + assertEquals(6L, snapshot.sum) + // Check that the 1L fell into the first value bucket + assertEquals(1L, snapshot.values[1]) + // Check that the 2L fell into the second value bucket + assertEquals(1L, snapshot.values[2]) + // Check that the 3L fell into the third value bucket + assertEquals(1L, snapshot.values[3]) + } + + @Test + fun `disabled custom distributions must not record data`() { + // Define a custom distribution metric which will be stored in "store1" + // It's lifetime is set to Lifetime.Ping so it should not record anything. + val metric = CustomDistributionMetricType( + disabled = true, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Attempt to store to the distribution + metric.accumulateSamples(listOf(0L).toLongArray()) + + // Check that nothing was recorded. + assertFalse("CustomDistributions without a lifetime should not record data.", + metric.testHasValue()) + } + + @Test(expected = NullPointerException::class) + fun `testGetValue() throws NullPointerException if nothing is stored`() { + // Define a custom distribution metric which will be stored in "store1" + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + metric.testGetValue() + } + + @Test + fun `The API saves to secondary pings`() { + // Define a custom distribution metric which will be stored in multiple stores + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "custom_distribution", + sendInPings = listOf("store1", "store2", "store3"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Accumulate a few values + metric.accumulateSamples(listOf(1L, 2L, 3L).toLongArray()) + + // Check that data was properly recorded in the second ping. + assertTrue(metric.testHasValue("store2")) + val snapshot = metric.testGetValue("store2") + // Check the sum + assertEquals(6L, snapshot.sum) + // Check that the 1L fell into the first bucket + assertEquals(1L, snapshot.values[1]) + // Check that the 2L fell into the second bucket + assertEquals(1L, snapshot.values[2]) + // Check that the 3L fell into the third bucket + assertEquals(1L, snapshot.values[3]) + + // Check that data was properly recorded in the third ping. + assertTrue(metric.testHasValue("store3")) + val snapshot2 = metric.testGetValue("store3") + // Check the sum + assertEquals(6L, snapshot2.sum) + // Check that the 1L fell into the first bucket + assertEquals(1L, snapshot2.values[1]) + // Check that the 2L fell into the second bucket + assertEquals(1L, snapshot2.values[2]) + // Check that the 3L fell into the third bucket + assertEquals(1L, snapshot2.values[3]) + } + + @Test + fun `The accumulateSamples API correctly stores values`() { + // Define a custom distribution metric which will be stored in multiple stores + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "custom_distribution_samples", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Accumulate a few values + val testSamples = (1L..3L).toList().toLongArray() + metric.accumulateSamples(testSamples) + + // Check that data was properly recorded in the second ping. + assertTrue(metric.testHasValue("store1")) + val snapshot = metric.testGetValue("store1") + // Check the sum + assertEquals(6L, snapshot.sum) + // Check that the 1L fell into the first bucket + assertEquals(1L, snapshot.values[1]) + // Check that the 2L fell into the second bucket + assertEquals(1L, snapshot.values[2]) + // Check that the 3L fell into the third bucket + assertEquals(1L, snapshot.values[3]) + } +} diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt new file mode 100644 index 00000000000..55c84281b0f --- /dev/null +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt @@ -0,0 +1,512 @@ +/* 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 mozilla.components.service.glean.storages + +import android.content.Context +import android.content.SharedPreferences +import androidx.test.core.app.ApplicationProvider +import kotlinx.coroutines.runBlocking +import mozilla.components.service.glean.collectAndCheckPingSchema +import mozilla.components.service.glean.private.Lifetime +import mozilla.components.service.glean.private.CustomDistributionMetricType +import mozilla.components.service.glean.error.ErrorRecording +import mozilla.components.service.glean.private.HistogramType +import mozilla.components.service.glean.private.PingType +import mozilla.components.service.glean.testing.GleanTestRule +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers +import org.mockito.Mockito +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class CustomDistributionsStorageEngineTest { + + @get:Rule + val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext()) + + @Test + fun `accumulate() properly updates the values in all stores`() { + val storeNames = listOf("store1", "store2") + + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "test_custom_distribution", + sendInPings = storeNames, + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Create a sample that will fall into the underflow bucket (bucket '0') so we can easily + // find it + val sample = 1L + CustomDistributionsStorageEngine.accumulateSamples( + metricData = metric, + samples = listOf(sample).toLongArray(), + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Check that the data was correctly set in each store. + for (storeName in storeNames) { + val snapshot = CustomDistributionsStorageEngine.getSnapshot( + storeName = storeName, + clearStore = true + ) + assertEquals(1, snapshot!!.size) + assertEquals(1L, snapshot["telemetry.test_custom_distribution"]?.values!![1]) + } + } + + @Test + fun `deserializer should correctly parse custom distributions`() { + // We are using the CustomDistributionData here as a way to turn the object + // into JSON for easy comparison + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.Ping, + name = "test_custom_distribution", + sendInPings = listOf("store1", "store2"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + val td = CustomDistributionData( + category = metric.category, + name = metric.name, + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + val persistedSample = mapOf( + "store1#telemetry.invalid_string" to "invalid_string", + "store1#telemetry.invalid_bool" to false, + "store1#telemetry.null" to null, + "store1#telemetry.invalid_int" to -1, + "store1#telemetry.invalid_list" to listOf("1", "2", "3"), + "store1#telemetry.invalid_int_list" to "[1,2,3]", + "store1#telemetry.invalid_td_name" to "{\"category\":\"telemetry\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", + "store1#telemetry.invalid_td_bucket_count" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":\"not an int!\",\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", + "store1#telemetry.invalid_td_range" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", + "store1#telemetry.invalid_td_range2" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[\"not\",\"numeric\"],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", + "store1#telemetry.invalid_td_histogram_type" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":-1,\"values\":{},\"sum\":0,\"time_unit\":2}", + "store1#telemetry.invalid_td_values" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{\"0\": \"nope\"},\"sum\":0,\"time_unit\":2}", + "store1#telemetry.invalid_td_sum" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":\"nope\",\"time_unit\":2}", + "store1#telemetry.invalid_td_time_unit" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":-1}", + "store1#telemetry.test_custom_distribution" to td.toJsonObject().toString() + ) + + val storageEngine = CustomDistributionsStorageEngineImplementation() + + // Create a fake application context that will be used to load our data. + val context = Mockito.mock(Context::class.java) + val sharedPreferences = Mockito.mock(SharedPreferences::class.java) + Mockito.`when`(sharedPreferences.all).thenAnswer { persistedSample } + Mockito.`when`(context.getSharedPreferences( + ArgumentMatchers.eq(storageEngine::class.java.canonicalName), + ArgumentMatchers.eq(Context.MODE_PRIVATE) + )).thenReturn(sharedPreferences) + Mockito.`when`(context.getSharedPreferences( + ArgumentMatchers.eq("${storageEngine::class.java.canonicalName}.PingLifetime"), + ArgumentMatchers.eq(Context.MODE_PRIVATE) + )).thenReturn(ApplicationProvider.getApplicationContext() + .getSharedPreferences("${storageEngine::class.java.canonicalName}.PingLifetime", + Context.MODE_PRIVATE)) + + storageEngine.applicationContext = context + val snapshot = storageEngine.getSnapshot(storeName = "store1", clearStore = true) + assertEquals(1, snapshot!!.size) + assertEquals(td.toJsonObject().toString(), + snapshot["telemetry.test_custom_distribution"]?.toJsonObject().toString()) + } + + @Test + fun `serializer should serialize custom distribution that matches schema`() { + val ping1 = PingType("store1", true) + + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + metric.accumulateSamples(listOf(1000000L).toLongArray()) + + collectAndCheckPingSchema(ping1) + } + + @Test + fun `serializer should correctly serialize custom distributions`() { + run { + val storageEngine = CustomDistributionsStorageEngineImplementation() + storageEngine.applicationContext = ApplicationProvider.getApplicationContext() + + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1", "store2"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Using the CustomDistributionData object here to easily turn the object into JSON + // for comparison purposes. + val td = CustomDistributionData( + category = metric.category, + name = metric.name, + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + td.accumulate(100L) + + runBlocking { + storageEngine.accumulateSamples( + metricData = metric, + samples = listOf(100L).toLongArray(), + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + } + + // Get snapshot from store1 + val json = storageEngine.getSnapshotAsJSON("store1", true) + // Check for correct JSON serialization + assertEquals("{\"${metric.identifier}\":${td.toJsonObject()}}", + json.toString() + ) + } + + // Create a new instance of storage engine to verify serialization to storage rather than + // to the cache + run { + val storageEngine = CustomDistributionsStorageEngineImplementation() + storageEngine.applicationContext = ApplicationProvider.getApplicationContext() + + val td = CustomDistributionData( + category = "telemetry", + name = "test_custom_distribution", + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + td.accumulate(100L) + + // Get snapshot from store1 + val json = storageEngine.getSnapshotAsJSON("store1", true) + // Check for correct JSON serialization + assertEquals("{\"telemetry.test_custom_distribution\":${td.toJsonObject()}}", + json.toString() + ) + } + } + + @Test + fun `custom distributions must not accumulate negative values`() { + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Attempt to accumulate a negative sample + metric.accumulateSamples(listOf(-1L).toLongArray()) + // Check that nothing was recorded. + assertFalse("Custom distributions must not accumulate negative values", + metric.testHasValue()) + + // Make sure that the errors have been recorded + assertEquals("Accumulating negative values must generate an error", + 1, + ErrorRecording.testGetNumRecordedErrors(metric, ErrorRecording.ErrorType.InvalidValue)) + } + + @Test + fun `underflow values accumulate in the first bucket`() { + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Attempt to accumulate an overflow sample + metric.accumulateSamples(listOf(0L).toLongArray()) + + // Check that custom distribution was recorded. + assertTrue("Accumulating underflow values records data", + metric.testHasValue()) + + // Make sure that the underflow landed in the correct (first) bucket + val snapshot = metric.testGetValue() + assertEquals("Accumulating overflow values should increment underflow bucket", + 1L, + snapshot.values[0]) + } + + @Test + fun `overflow values accumulate in the last bucket`() { + val rangeMax = 60000L + + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, rangeMax), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Attempt to accumulate an overflow sample + metric.accumulateSamples(listOf(rangeMax + 100 * 1000000).toLongArray()) + + // Check that custom distribution was recorded. + assertTrue("Accumulating overflow values records data", + metric.testHasValue()) + + // Make sure that the overflow landed in the correct (last) bucket + val snapshot = metric.testGetValue() + assertEquals("Accumulating overflow values should increment last bucket", + 1L, + snapshot.values[rangeMax]) + } + + @Test + fun `getBuckets() correctly populates the buckets property`() { + // Hand calculated values using current default range 0 - 60000 and bucket count of 100. + // NOTE: The final bucket, regardless of width, represents the overflow bucket to hold any + // values beyond the maximum (in this case the maximum is 60000) + val testBuckets: List = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, + 19, 21, 23, 25, 28, 31, 34, 38, 42, 46, 51, 56, 62, 68, 75, 83, 92, 101, 111, 122, 135, + 149, 164, 181, 200, 221, 244, 269, 297, 328, 362, 399, 440, 485, 535, 590, 651, 718, + 792, 874, 964, 1064, 1174, 1295, 1429, 1577, 1740, 1920, 2118, 2337, 2579, 2846, 3140, + 3464, 3822, 4217, 4653, 5134, 5665, 6250, 6896, 7609, 8395, 9262, 10219, 11275, 12440, + 13726, 15144, 16709, 18436, 20341, 22443, 24762, 27321, 30144, 33259, 36696, 40488, + 44672, 49288, 54381, 60000) + + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Accumulate a sample to force the lazy loading of `buckets` to occur + metric.accumulateSamples(listOf(0L).toLongArray()) + + // Check that custom distribution was recorded. + assertTrue("Accumulating values records data", metric.testHasValue()) + + // Make sure that the sample in the correct (underflow) bucket + val snapshot = metric.testGetValue() + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[0]) + + // verify buckets lists worked + assertNotNull("Buckets must not be null", snapshot.buckets) + + assertEquals("Bucket calculation failed", testBuckets, snapshot.buckets) + } + + @Test + fun `samples go in the correct bucket`() { + val td = CustomDistributionData( + category = "telemetry", + name = "test_custom_distribution", + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + for (i in (0..60)) { + val x = i * 1000L + val bucket = td.findBucket(x) + assert(bucket <= x) + } + + val td2 = CustomDistributionData( + category = "telemetry", + name = "test_custom_distribution", + rangeMin = 10000L, + rangeMax = 50000L, + bucketCount = 50, + histogramType = HistogramType.Exponential + ) + + for (i in (0..60)) { + val x = i * 1000L + val bucket = td2.findBucket(x) + assert(bucket <= x) + } + } + + @Test + fun `linear bucketing`() { + val td = CustomDistributionData( + category = "telemetry", + name = "test_custom_distribution", + rangeMin = 0L, + rangeMax = 99L, + bucketCount = 100, + histogramType = HistogramType.Linear + ) + assertEquals(100, td.buckets.size) + + for (i in (0L until 100L)) { + val bucket = td.findBucket(i) + assert(bucket <= i) + } + + val td2 = CustomDistributionData( + category = "telemetry", + name = "test_custom_distribution", + rangeMin = 50L, + rangeMax = 50000L, + bucketCount = 50, + histogramType = HistogramType.Linear + ) + assertEquals(50, td2.buckets.size) + + for (i in (0..60)) { + val x: Long = i * 1000L + val bucket = td2.findBucket(x) + assert(bucket <= x) + } + } + + @Test + fun `accumulate finds the correct bucket`() { + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + range = listOf(0L, 60000L), + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Check that a few values correctly fall into the correct buckets (as calculated by hand) + // to validate the linear bucket search algorithm + + // Attempt to accumulate a sample to force metric to be stored + metric.accumulateSamples(listOf(1L, 10L, 100L, 1000L, 10000L).toLongArray()) + + // Check that custom distribution was recorded. + assertTrue("Accumulating values records data", metric.testHasValue()) + + // Make sure that the samples are in the correct buckets + val snapshot = metric.testGetValue() + + // Check sum and count + assertEquals("Accumulating updates the sum", 11111, snapshot.sum) + assertEquals("Accumulating updates the count", 5, snapshot.count) + + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[1]) + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[10]) + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[92]) + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[964]) + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[9262]) + } + + @Test + fun `toJsonObject correctly converts a CustomDistributionData object`() { + // Define a CustomDistributionData object + val tdd = CustomDistributionData( + category = "telemetry", + name = "test_custom_distribution", + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Exponential + ) + + // Accumulate some samples to populate sum and values properties + tdd.accumulate(1L) + tdd.accumulate(2L) + tdd.accumulate(3L) + + // Convert to JSON object using toJsonObject() + val jsonTdd = tdd.toJsonObject() + + // Verify properties + assertEquals("JSON category must match Custom Distribution category", + "telemetry", jsonTdd.getString("category")) + assertEquals("JSON name must match Custom Distribution name", + "test_custom_distribution", jsonTdd.getString("name")) + assertEquals("JSON bucket count must match Custom Distribution bucket count", + tdd.bucketCount, jsonTdd.getInt("bucket_count")) + assertEquals("JSON name must match Custom Distribution name", + "test_custom_distribution", jsonTdd.getString("name")) + val jsonRange = jsonTdd.getJSONArray("range") + assertEquals("JSON range minimum must match Custom Distribution range minimum", + tdd.rangeMin, jsonRange.getLong(0)) + assertEquals("JSON range maximum must match Custom Distribution range maximum", + tdd.rangeMax, jsonRange.getLong(1)) + assertEquals("JSON histogram type must match Custom Distribution histogram type", + tdd.histogramType.toString().toLowerCase(), jsonTdd.getString("histogram_type")) + val jsonValue = jsonTdd.getJSONObject("values") + assertEquals("JSON values must match Custom Distribution values", + tdd.values[1], jsonValue.getLong("1")) + assertEquals("JSON values must match Custom Distribution values", + tdd.values[2], jsonValue.getLong("2")) + assertEquals("JSON values must match Custom Distribution values", + tdd.values[3], jsonValue.getLong("3")) + assertEquals("JSON sum must match Custom Distribution sum", + tdd.sum, jsonTdd.getLong("sum")) + } +} From 3b12522a0e551de1416fcf8f0a51069377093e97 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 7 Aug 2019 10:45:02 -0400 Subject: [PATCH 32/38] Address comments in the PR --- .../private/CustomDistributionMetricType.kt | 30 +++++-- .../private/TimingDistributionMetricType.kt | 18 ++-- .../CustomDistributionsStorageEngine.kt | 19 ++-- .../CustomDistributionMetricTypeTest.kt | 15 ++-- .../CustomDistributionsStorageEngineTest.kt | 89 ++++++++++++++----- 5 files changed, 118 insertions(+), 53 deletions(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt index 79651654f72..273ea9c1e73 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/CustomDistributionMetricType.kt @@ -13,6 +13,17 @@ import mozilla.components.support.base.log.logger.Logger /** * This implements the developer facing API for recording custom distribution metrics. * + * Custom distributions are histograms with the following parameters that are settable on a + * per-metric basis: + * + * - `rangeMin`/`rangeMax`: The minimum and maximum values + * - `bucketCount`: The number of histogram buckets + * - `histogramType`: Whether the bucketing is linear or exponential + * + * This metric exists primarily for backward compatibility with histograms in + * legacy (pre-Glean) telemetry, and its use is not recommended for newly-created + * metrics. + * * Instances of this class type are automatically generated by the parsers at build time, * allowing developers to record values that were previously registered in the metrics.yaml file. */ @@ -22,16 +33,23 @@ data class CustomDistributionMetricType( override val lifetime: Lifetime, override val name: String, override val sendInPings: List, - val range: List, + val rangeMin: Long, + val rangeMax: Long, val bucketCount: Int, val histogramType: HistogramType ) : CommonMetricData, HistogramBase { - init { - assert(range.size == 2) - } private val logger = Logger("glean/CustomDistributionMetricType") + /** + * Accumulates the provided samples in the metric. + * + * The unit of the samples is entirely defined by the user. We encourage the author of the + * metric to provide a `unit` parameter in the `metrics.yaml` file, but that has no effect + * in the client and there is no unit conversion performed here. + * + * @param samples the [LongArray] holding the samples to be recorded by the metric. + */ override fun accumulateSamples(samples: LongArray) { if (!shouldRecord(logger)) { return @@ -42,8 +60,8 @@ data class CustomDistributionMetricType( CustomDistributionsStorageEngine.accumulateSamples( metricData = this@CustomDistributionMetricType, samples = samples, - rangeMin = range[0], - rangeMax = range[1], + rangeMin = rangeMin, + rangeMax = rangeMax, bucketCount = bucketCount, histogramType = histogramType ) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt index 2cef2bfef16..5bd25b53a43 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/private/TimingDistributionMetricType.kt @@ -92,14 +92,16 @@ data class TimingDistributionMetricType( } /** - * Accumulates the provided samples in the metric. - * - * Please note that this assumes that the provided samples are in `timeUnit` - * and will be converted to nanoseconds for storage and sending in the ping. - * - * @param samples the [LongArray] holding the samples to be recorded by the metric, in - * the unit specified by `timeUnit`. - */ + * Accumulates the provided samples in the metric. + * + * Please note that this assumes that the provided samples are already in the + * "unit" declared by the instance of the implementing metric type (e.g. if the + * implementing class is a [TimingDistributionMetricType] and the instance this + * method was called on is using [TimeUnit.Second], then `samples` are assumed + * to be in that unit). + * + * @param samples the [LongArray] holding the samples to be recorded by the metric. + */ override fun accumulateSamples(samples: LongArray) { if (!shouldRecord(logger)) { return diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt index bd9cf1a382c..d56404f0468 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt @@ -4,7 +4,6 @@ package mozilla.components.service.glean.storages -import android.annotation.SuppressLint import android.content.SharedPreferences import androidx.annotation.VisibleForTesting import mozilla.components.service.glean.error.ErrorRecording @@ -19,14 +18,9 @@ import org.json.JSONArray import org.json.JSONObject /** - * This singleton handles the in-memory storage logic for timing distributions. It is meant to be - * used by the Timing Distribution API and the ping assembling objects. - * - * This class contains a reference to the Android application Context. While the IDE warns - * us that this could leak, the application context lives as long as the application and this - * object. For this reason, we should be safe to suppress the IDE warning. + * This singleton handles the in-memory storage logic for custom distributions. It is meant to be + * used by the Custom Distribution API and the ping assembling objects. */ -@SuppressLint("StaticFieldLeak") internal object CustomDistributionsStorageEngine : CustomDistributionsStorageEngineImplementation() internal open class CustomDistributionsStorageEngineImplementation( @@ -145,7 +139,7 @@ internal open class CustomDistributionsStorageEngineImplementation( * @param rangeMax the maximum value that can be represented * @param histogramType the [HistogramType] representing the bucket layout * @param values a map containing the bucket index mapped to the accumulated count - * @param sum the accumulated sum of all the samples in the timing distribution + * @param sum the accumulated sum of all the samples in the custom distribution */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) data class CustomDistributionData( @@ -310,10 +304,9 @@ data class CustomDistributionData( @Suppress("MagicNumber") private fun getBucketsLinear(): List { // Written to match the bucket generation on legacy desktop telemetry: - // https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py#65 + // https://searchfox.org/mozilla-central/rev/e0b0c38ee83f99d3cf868bad525ace4a395039f1/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py#65 - val result: MutableList = mutableListOf() - result.add(0) + val result: MutableList = mutableListOf(0L) val dmin = rangeMin.toDouble() val dmax = rangeMax.toDouble() @@ -334,7 +327,7 @@ data class CustomDistributionData( */ private fun getBucketsExponential(): List { // Written to match the bucket generation on legacy desktop telemetry: - // https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py#75 + // https://searchfox.org/mozilla-central/rev/e0b0c38ee83f99d3cf868bad525ace4a395039f1/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py#75 // This algorithm calculates the bucket sizes using a natural log approach to get // `bucketCount` number of buckets, exponentially spaced between `range[MIN]` and diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt index cf4f5a247d3..f9b4b508514 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/private/CustomDistributionMetricTypeTest.kt @@ -34,7 +34,8 @@ class CustomDistributionMetricTypeTest { lifetime = Lifetime.Ping, name = "custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -67,7 +68,8 @@ class CustomDistributionMetricTypeTest { lifetime = Lifetime.Ping, name = "custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -89,7 +91,8 @@ class CustomDistributionMetricTypeTest { lifetime = Lifetime.Ping, name = "custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -105,7 +108,8 @@ class CustomDistributionMetricTypeTest { lifetime = Lifetime.Ping, name = "custom_distribution", sendInPings = listOf("store1", "store2", "store3"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -147,7 +151,8 @@ class CustomDistributionMetricTypeTest { lifetime = Lifetime.Ping, name = "custom_distribution_samples", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt index 55c84281b0f..2d6a6697be4 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt @@ -42,7 +42,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.Ping, name = "test_custom_distribution", sendInPings = storeNames, - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -80,7 +81,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.Ping, name = "test_custom_distribution", sendInPings = listOf("store1", "store2"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -100,14 +102,13 @@ class CustomDistributionsStorageEngineTest { "store1#telemetry.invalid_int" to -1, "store1#telemetry.invalid_list" to listOf("1", "2", "3"), "store1#telemetry.invalid_int_list" to "[1,2,3]", - "store1#telemetry.invalid_td_name" to "{\"category\":\"telemetry\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_bucket_count" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":\"not an int!\",\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_range" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_range2" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[\"not\",\"numeric\"],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_histogram_type" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":-1,\"values\":{},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_values" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{\"0\": \"nope\"},\"sum\":0,\"time_unit\":2}", - "store1#telemetry.invalid_td_sum" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":\"nope\",\"time_unit\":2}", - "store1#telemetry.invalid_td_time_unit" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0,\"time_unit\":-1}", + "store1#telemetry.invalid_td_name" to "{\"category\":\"telemetry\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0}", + "store1#telemetry.invalid_td_bucket_count" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":\"not an int!\",\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0}", + "store1#telemetry.invalid_td_range" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":0}", + "store1#telemetry.invalid_td_range2" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[\"not\",\"numeric\"],\"histogram_type\":1,\"values\":{},\"sum\":0}", + "store1#telemetry.invalid_td_histogram_type" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":-1,\"values\":{},\"sum\":0}", + "store1#telemetry.invalid_td_values" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{\"0\": \"nope\"},\"sum\":0}", + "store1#telemetry.invalid_td_sum" to "{\"category\":\"telemetry\",\"name\":\"test_custom_distribution\",\"bucket_count\":100,\"range\":[0,60000,12],\"histogram_type\":1,\"values\":{},\"sum\":\"nope\"}", "store1#telemetry.test_custom_distribution" to td.toJsonObject().toString() ) @@ -145,7 +146,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -167,7 +169,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1", "store2"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -237,7 +240,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -263,7 +267,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -293,7 +298,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, rangeMax), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -313,7 +319,7 @@ class CustomDistributionsStorageEngineTest { } @Test - fun `getBuckets() correctly populates the buckets property`() { + fun `getBuckets() correctly populates the buckets properly for exponential distributions`() { // Hand calculated values using current default range 0 - 60000 and bucket count of 100. // NOTE: The final bucket, regardless of width, represents the overflow bucket to hold any // values beyond the maximum (in this case the maximum is 60000) @@ -332,7 +338,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -355,7 +362,7 @@ class CustomDistributionsStorageEngineTest { } @Test - fun `samples go in the correct bucket`() { + fun `samples go in the correct bucket for exponential bucketing`() { val td = CustomDistributionData( category = "telemetry", name = "test_custom_distribution", @@ -388,7 +395,7 @@ class CustomDistributionsStorageEngineTest { } @Test - fun `linear bucketing`() { + fun `validate the generated linear buckets`() { val td = CustomDistributionData( category = "telemetry", name = "test_custom_distribution", @@ -422,7 +429,7 @@ class CustomDistributionsStorageEngineTest { } @Test - fun `accumulate finds the correct bucket`() { + fun `accumulate finds the correct bucket for exponential distributions`() { // Define a custom distribution metric, which will be stored in "store1". val metric = CustomDistributionMetricType( disabled = false, @@ -430,7 +437,8 @@ class CustomDistributionsStorageEngineTest { lifetime = Lifetime.User, name = "test_custom_distribution", sendInPings = listOf("store1"), - range = listOf(0L, 60000L), + rangeMin = 0L, + rangeMax = 60000L, bucketCount = 100, histogramType = HistogramType.Exponential ) @@ -463,6 +471,45 @@ class CustomDistributionsStorageEngineTest { 1L, snapshot.values[9262]) } + @Test + fun `accumulate finds the correct bucket for linear distributions`() { + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Linear + ) + + // Check that a few values correctly fall into the correct buckets (as calculated by hand) + // to validate the linear bucket search algorithm + + // Attempt to accumulate a sample to force metric to be stored + metric.accumulateSamples(listOf(1L, 10L, 100L, 1000L, 10000L).toLongArray()) + + // Check that custom distribution was recorded. + assertTrue("Accumulating values records data", metric.testHasValue()) + + // Make sure that the samples are in the correct buckets + val snapshot = metric.testGetValue() + + // Check sum and count + assertEquals("Accumulating updates the sum", 11111, snapshot.sum) + assertEquals("Accumulating updates the count", 5, snapshot.count) + + assertEquals("Accumulating should increment correct bucket", + 3L, snapshot.values[0]) + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[612]) + assertEquals("Accumulating should increment correct bucket", + 1L, snapshot.values[9796]) + } + @Test fun `toJsonObject correctly converts a CustomDistributionData object`() { // Define a CustomDistributionData object From 894410c1fe98a9f88b897f9bd65df0e1f3bfaf8b Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 8 Aug 2019 15:48:42 -0400 Subject: [PATCH 33/38] Don't send parameters in the payload --- .../CustomDistributionsStorageEngine.kt | 32 ++++++++++- .../CustomDistributionsStorageEngineTest.kt | 56 ++++++++++++++++++- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt index d56404f0468..304d69589db 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt @@ -120,7 +120,7 @@ internal open class CustomDistributionsStorageEngineImplementation( return getSnapshot(storeName, clearStore)?.let { dataMap -> val jsonObj = JSONObject() dataMap.forEach { - jsonObj.put(it.key, it.value.toJsonObject()) + jsonObj.put(it.key, it.value.toJsonPayloadObject()) } return jsonObj } @@ -295,6 +295,36 @@ data class CustomDistributionData( )) } + /** + * Helper function to build the [CustomDistributionData] into a JSONObject for sending in the + * ping payload. Compared to [toJsonObject] which is designed for lossless roundtripping: + * + * - this does not include the bucketing parameters + * - all buckets [0, max) are inserted into values + */ + internal fun toJsonPayloadObject(): JSONObject { + // Include all buckets [0, max), where max is the maximum bucket with + // any value recorded. + val contiguousValues = if (!values.isEmpty()) { + val bucketMax = values.keys.max()!! + val contiguousValues = mutableMapOf() + for (bucketMin in buckets) { + contiguousValues["$bucketMin"] = values.getOrDefault(bucketMin, 0) + if (bucketMin > bucketMax) { + break + } + } + contiguousValues + } else { + values + } + + return JSONObject(mapOf( + "values" to contiguousValues, + "sum" to sum + )) + } + /** * Helper function to generate the list of linear bucket min values used when accumulating * to the correct buckets. diff --git a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt index 2d6a6697be4..274cc0f3029 100644 --- a/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt +++ b/components/service/glean/src/test/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngineTest.kt @@ -201,7 +201,7 @@ class CustomDistributionsStorageEngineTest { // Get snapshot from store1 val json = storageEngine.getSnapshotAsJSON("store1", true) // Check for correct JSON serialization - assertEquals("{\"${metric.identifier}\":${td.toJsonObject()}}", + assertEquals("{\"${metric.identifier}\":${td.toJsonPayloadObject()}}", json.toString() ) } @@ -225,7 +225,7 @@ class CustomDistributionsStorageEngineTest { // Get snapshot from store1 val json = storageEngine.getSnapshotAsJSON("store1", true) // Check for correct JSON serialization - assertEquals("{\"telemetry.test_custom_distribution\":${td.toJsonObject()}}", + assertEquals("{\"telemetry.test_custom_distribution\":${td.toJsonPayloadObject()}}", json.toString() ) } @@ -511,7 +511,38 @@ class CustomDistributionsStorageEngineTest { } @Test - fun `toJsonObject correctly converts a CustomDistributionData object`() { + fun `toJsonPayloadObject correctly inserts zero buckets`() { + // Define a custom distribution metric, which will be stored in "store1". + val metric = CustomDistributionMetricType( + disabled = false, + category = "telemetry", + lifetime = Lifetime.User, + name = "test_custom_distribution", + sendInPings = listOf("store1"), + rangeMin = 0L, + rangeMax = 60000L, + bucketCount = 100, + histogramType = HistogramType.Linear + ) + + metric.accumulateSamples(listOf(10000L).toLongArray()) + + // Make sure that the samples are in the correct buckets + val snapshot = metric.testGetValue() + val payload = snapshot.toJsonPayloadObject() + val payloadValues = payload.getJSONObject("values") + + assertEquals(18, payloadValues.length()) + assertEquals(1L, payloadValues["9796"]) + for (key in payloadValues.keys()) { + if (key != "9796") { + assertEquals(0L, payloadValues[key]) + } + } + } + + @Test + fun `toJsonObject and toJsonPayloadObject correctly converts a CustomDistributionData object`() { // Define a CustomDistributionData object val tdd = CustomDistributionData( category = "telemetry", @@ -555,5 +586,24 @@ class CustomDistributionsStorageEngineTest { tdd.values[3], jsonValue.getLong("3")) assertEquals("JSON sum must match Custom Distribution sum", tdd.sum, jsonTdd.getLong("sum")) + + // Convert to JSON object using toJsonObject() + val jsonPayload = tdd.toJsonPayloadObject() + + // Verify properties + assertEquals(2, jsonPayload.length()) + val jsonPayloadValue = jsonPayload.getJSONObject("values") + assertEquals("JSON values must match Custom Distribution values", + 0, jsonPayloadValue.getLong("0")) + assertEquals("JSON values must match Custom Distribution values", + tdd.values[1], jsonPayloadValue.getLong("1")) + assertEquals("JSON values must match Custom Distribution values", + tdd.values[2], jsonPayloadValue.getLong("2")) + assertEquals("JSON values must match Custom Distribution values", + tdd.values[3], jsonPayloadValue.getLong("3")) + assertEquals("JSON values must match Custom Distribution values", + 0, jsonPayloadValue.getLong("4")) + assertEquals("JSON sum must match Custom Distribution sum", + tdd.sum, jsonPayload.getLong("sum")) } } From c0559cabf2f49375f2f711e177129dfd0a0855b4 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 9 Aug 2019 15:34:53 -0400 Subject: [PATCH 34/38] Don't use new API --- .../service/glean/storages/CustomDistributionsStorageEngine.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt index 304d69589db..c336ef934c8 100644 --- a/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt +++ b/components/service/glean/src/main/java/mozilla/components/service/glean/storages/CustomDistributionsStorageEngine.kt @@ -309,7 +309,7 @@ data class CustomDistributionData( val bucketMax = values.keys.max()!! val contiguousValues = mutableMapOf() for (bucketMin in buckets) { - contiguousValues["$bucketMin"] = values.getOrDefault(bucketMin, 0) + contiguousValues["$bucketMin"] = values.getOrElse(bucketMin) { 0L } if (bucketMin > bucketMax) { break } From 5000054fd8777b829bf2c701f91c5d70705d1170 Mon Sep 17 00:00:00 2001 From: Travis Long Date: Mon, 12 Aug 2019 12:25:42 -0500 Subject: [PATCH 35/38] Update service-experiments README.md --- components/service/experiments/KintoSchema.md | 375 ++++++++++++++++++ components/service/experiments/README.md | 35 +- 2 files changed, 396 insertions(+), 14 deletions(-) create mode 100644 components/service/experiments/KintoSchema.md diff --git a/components/service/experiments/KintoSchema.md b/components/service/experiments/KintoSchema.md new file mode 100644 index 00000000000..5a3d9338358 --- /dev/null +++ b/components/service/experiments/KintoSchema.md @@ -0,0 +1,375 @@ +# Kinto Schema + +This document contains the information about the Kinto schema and UI schema needed to run dev experiments +on the "Dev" Kinto instance located at https://kinto.dev.mozaws.net. + +## JSON Schema + +```JSON +{ + "type": "object", + "required": [ + "id", + "description", + "match", + "buckets", + "branches" + ], + "properties": { + "id": { + "title": "Experiment id", + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "description": { + "title": "Description", + "type": "string" + }, + "buckets": { + "title": "Buckets", + "type": "object", + "description": "Each user is assigned a random bucket from 0 to 999. Select the bucket ranges here to control the enrolled population size.", + "required": [ + "start", + "count" + ], + "properties": { + "start": { + "mininum": 0, + "maximum": 999, + "type": "number" + }, + "count": { + "mininum": 0, + "maximum": 1000, + "type": "number" + } + } + }, + "branches": { + "title": "Branches", + "type": "array", + "required": [ + "name", + "ratio" + ], + "default": [], + "uniqueItems": true, + "minItems": 1, + "description": "Each experiment needs to specify one or more branches. Each branch has a name and a ratio. An enrolled user is assigned one branch randomly, with the probabilities weighted per the ratio.", + "items": { + "description": "One experiment branch.", + "title": "Branch", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The branch name. This is what product code uses to decide which branch logic to execute.", + "minLength": 1, + "maxLength": 100 + }, + "ratio": { + "type": "number", + "description": "The branches ratio is the probabilistic weight for random branch assignment.", + "mininum": 1, + "maximum": 1000, + "default": 1 + } + } + } + }, + "match": { + "title": "Matching", + "type": "object", + "description": "A list of optional matchers, which allow restricting the experiment to e.g. specific application ids.", + "properties": { + "app_id": { + "type": "string", + "description": "Match specific application ids. A regex. E.g.: ^org.mozilla.fennec|org.mozilla.firefox_beta|org.mozilla.firefox$", + "minLength": 1, + "maxLength": 1000 + }, + "app_display_version": { + "description": "The application's version number. A regex. E.g.: '47.0a1', '46.0'", + "type": "string" + }, + "app_min_version": { + "description": "The application's minimum version number. E.g.: '47.0.11', '46.0'", + "type": "string" + }, + "app_max_version": { + "description": "The application's maximum version number. E.g.: '47.0.11', '46.0'", + "type": "string" + }, + "locale_country": { + "description": "Match country, pulled from the default locale. A regex. E.g.: USA|ITA", + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "locale_language": { + "description": "Language, pulled from the default locale. A regex. E.g.: eng|esp", + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "device_model": { + "description": "Device name. A regex.", + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "device_manufacturer": { + "description": "Device manufacturer", + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "regions": { + "default": [], + "description": "Compared with GeoIP lookup, where supported.", + "items": { + "default": "", + "description": "Similar to a GeoIP lookup", + "minLength": 1, + "maxLength": 1000, + "title": "Regions", + "type": "string" + }, + "title": "Regions", + "type": "array", + "uniqueItems": true + }, + "debug_tags": { + "default": [], + "description": "Target specific debug tags only. This allows testing of experiments for only specific active users for QA etc.", + "items": { + "default": "", + "description": "A debug tag set through the libraries debug activity.", + "minLength": 1, + "title": "Debug tag", + "type": "string" + }, + "title": "Debug tags", + "type": "array", + "uniqueItems": true + } + } + } + } +} +``` + +## UI Schema + +```JSON +{ + "sort": "-last_modified", + "displayFields": [ + "id", + "description" + ], + "attachment": { + "enabled": false, + "required": false + }, + "schema": { + "properties": { + "id": { + "type": "string", + "maxLength": 100, + "title": "Experiment id", + "minLength": 1 + }, + "buckets": { + "description": "Each user is assigned a random bucket from 0 to 999. Select the bucket ranges here to control the enrolled population size.", + "properties": { + "start": { + "type": "number", + "mininum": 0, + "maximum": 999 + }, + "count": { + "type": "number", + "mininum": 0, + "maximum": 1000 + } + }, + "type": "object", + "required": [ + "start", + "count" + ], + "title": "Buckets" + }, + "description": { + "type": "string", + "title": "Description" + }, + "branches": { + "description": "Each experiment needs to specify one or more branches. Each branch has a name and a ratio. An enrolled user is assigned one branch randomly, with the probabilities weighted per the ratio.", + "required": [ + "name", + "ratio" + ], + "title": "Branches", + "items": { + "description": "One experiment branch.", + "properties": { + "ratio": { + "description": "The branches ratio is the probabilistic weight for random branch assignment.", + "type": "number", + "default": 1, + "mininum": 1, + "maximum": 1000 + }, + "name": { + "description": "The branch name. This is what product code uses to decide which branch logic to execute.", + "type": "string", + "maxLength": 100, + "minLength": 1 + } + }, + "type": "object", + "title": "Branch" + }, + "type": "array", + "minItems": 1, + "uniqueItems": true, + "default": [] + }, + "match": { + "description": "A list of optional matchers, which allow restricting the experiment to e.g. specific application ids.", + "properties": { + "app_id": { + "description": "Match specific application ids. A regex. E.g.: ^org.mozilla.fennec|org.mozilla.firefox_beta|org.mozilla.firefox$", + "type": "string", + "maxLength": 1000, + "minLength": 1 + }, + "app_display_version": { + "description": "The application's version number. A regex. E.g.: '47.0a1', '46.0'", + "type": "string" + }, + "app_min_version": { + "description": "The application's minimum version number. E.g.: '47.0.11', '46.0'", + "type": "string" + }, + "app_max_version": { + "description": "The application's maximum version number. E.g.: '47.0.11', '46.0'", + "type": "string" + }, + "device_manufacturer": { + "description": "Device manufacturer", + "type": "string", + "maxLength": 1000, + "minLength": 1 + }, + "debug_tags": { + "description": "Target specific debug tags only. This allows testing of experiments for only specific active users for QA etc.", + "title": "Debug tags", + "items": { + "description": "A debug tag set through the libraries debug activity.", + "type": "string", + "title": "Debug tag", + "default": "", + "minLength": 1 + }, + "type": "array", + "uniqueItems": true, + "default": [] + }, + "locale_country": { + "description": "Match country, pulled from the default locale. A regex. E.g.: USA|ITA", + "type": "string", + "maxLength": 1000, + "minLength": 1 + }, + "regions": { + "description": "Compared with GeoIP lookup, where supported.", + "title": "Regions", + "items": { + "description": "Similar to a GeoIP lookup", + "maxLength": 1000, + "title": "Regions", + "type": "string", + "minLength": 1, + "default": "" + }, + "type": "array", + "uniqueItems": true, + "default": [] + }, + "device_model": { + "description": "Device name. A regex.", + "type": "string", + "maxLength": 1000, + "minLength": 1 + }, + "locale_language": { + "description": "Language, pulled from the default locale. A regex. E.g.: eng|esp", + "type": "string", + "maxLength": 1000, + "minLength": 1 + } + }, + "type": "object", + "title": "Matching" + } + }, + "type": "object", + "required": [ + "id", + "description", + "match", + "buckets", + "branches" + ] + }, + "uiSchema": { + "buckets": { + "ui:order": [ + "start", + "count" + ] + }, + "description": { + "ui:widget": "textarea" + }, + "match": { + "ui:order": [ + "app_id", + "app_display_version", + "app_min_version", + "app_max_version", + "locale_language", + "locale_country", + "device_model", + "device_manufacturer", + "regions", + "debug_tags" + ] + }, + "ui:order": [ + "id", + "description", + "buckets", + "branches", + "match" + ] + }, + "cache_expires": 0 +} +``` + +## Where to add this + +For testing create a collection `mobile-experiments` in the `main` bucket on the [Kinto dev server](https://kinto.dev.mozaws.net/v1/admin/). + +## Records list columns + +What's added in "Records list columns" is what get's shown in the record lists overview. +We want: +- id +- description \ No newline at end of file diff --git a/components/service/experiments/README.md b/components/service/experiments/README.md index a93420882ed..8d7730ca88e 100644 --- a/components/service/experiments/README.md +++ b/components/service/experiments/README.md @@ -18,15 +18,15 @@ implementation "org.mozilla.components:service-experiments:{latest-version}" ``` ### Initializing the Experiments library -In order to use the library, first you have to initialize it by calling `Experiments.initialize()`. You do this once per app launch -(typically in your `Application` class `onCreate` method). You simply have to call `Experiments.initialize()` and -provide the `applicationContext` (and optionally a `Configuration` object), like this: + +In order to use the library, first you have to initialize it by calling `Experiments.initialize()`. +You do this once per app launch (typically in your `Application` class `onCreate` method). You +simply have to call `Experiments.initialize()` and provide the `applicationContext` (and optionally +a `Configuration` object), like this: ```Kotlin class SampleApp : Application() { override fun onCreate() { - // Glean needs to be initialized first. - Glean.initialize(/* ... */) Experiments.initialize( applicationContext, configuration // This is optional, e.g. for overriding the fetch client. @@ -35,21 +35,26 @@ class SampleApp : Application() { } ``` -Note that this library depends on the Glean library, which has to be initialized first. See the [Glean README](../glean/README.md) for more details. +This library makes use of [Glean](https://mozilla.github.io/glean/book/index.html) for reporting +experiment enrollment. If Glean is not used and initialized by the application, the recording +methods are a no-op. ### Updating of experiments -The library updates it's list of experiments automatically and async from Kinto on library initialization. As this is asynchronous, it will not have immediate effect. +The library updates its list of experiments automatically and asynchronously from Kinto on library +initialization. As this is asynchronous, it will not have immediate effect. -Afterwards, the list of experiments will be updated every 6 hours. +Afterwards, the list of experiments will be updated in the background every 6 hours. ### Checking if a user is part of an experiment -In order to check if a user is part of a specific experiment, `Experiments` provides a Kotlin-friendly -`withExperiment` API. You pass the id of the experiment you want to check and if the client is in the experiment, you get the selected branch name passed: + +In order to check if a user is part of a specific experiment, `Experiments` provides a +Kotlin-friendly `withExperiment` API. You pass the id of the experiment you want to check and if the +client is in the experiment, you get the selected branch name passed: ```Kotlin -Experiments.withExperiment("button-color-experiment") { - when(it) { // `it` is the branch name. +Experiments.withExperiment("button-color-experiment") { branchName -> + when(branchName) { "red" -> button.setBackgroundColor(Color.RED) "control" -> button.setBackgroundColor(DEFAULT_COLOR) } @@ -64,14 +69,15 @@ For any technical tests, we do have a Kinto dev server available, which can be f The admin interface is [here](https://kinto.dev.mozaws.net/v1/admin/). For setting up a testing setup we can: - [Create a collection in the main bucket](https://kinto.dev.mozaws.net/v1/admin/#/buckets/main/collections/create). - The *collection id* should be `mobile-experiments`. - - The *JSON schema* should have [this content](https://gist.github.com/travis79/c112d803dfcd84cb5f854f5b22bfcd0f#file-json-schema-json). - - The *UI schema* should have [this content](https://gist.github.com/travis79/c112d803dfcd84cb5f854f5b22bfcd0f#file-ui-schema-json). + - The *JSON schema* should have [this content](KintoSchema.md#JSON-Schema) + - The *UI schema* should have [this content](KintoSchema.md#UI-Schema) - The *Records list columns* should contain `id` and `description`. - Click *Create collection* - In the [`mobile-experiments` record list](https://kinto.dev.mozaws.net/v1/admin/#/buckets/main/collections/mobile-experiments/records), create new entries for experiments as needed. - In the mobile application, use the debug commands below to switch to the `dev` endpoint. ### ExperimentsDebugActivity usage + Experiments exports the [`ExperimentsDebugActivity`](src/main/java/mozilla/components/service/experiments/debug/ExperimentsDebugActivity.kt) that can be used to trigger functionality or toggle debug features on or off. Users can invoke this special activity, at run-time, using the following [`adb`](https://developer.android.com/studio/command-line/adb) command: @@ -163,6 +169,7 @@ An individual experiment record looks e.g. like this: ``` ### Experiment fields + The experiments records in Kinto contain the following properties: | Name | Type | Required | Description | Example | From 132ad7383c2f4015d61f2ecc1749e0dcd1960d64 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Mon, 12 Aug 2019 19:46:32 +0200 Subject: [PATCH 36/38] Issue #1200: Disable taskcluster checks for bors tmp branches. --- .taskcluster.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.taskcluster.yml b/.taskcluster.yml index 11b0bae78c9..5c0f33ab3cc 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -157,7 +157,7 @@ tasks: metadata: name: 'Android Components - Decision task (Pull Request #${pull_request_number})' description: 'Building and testing Android components - triggered by [#${pull_request_number}](${pull_request_url})' - - $if: 'tasks_for == "github-push" && head_branch[:10] != "refs/tags/"' + - $if: 'tasks_for == "github-push" && head_branch[:10] != "refs/tags/" && head_branch != "staging.tmp" && head_branch != "trying.tmp"' then: $mergeDeep: - {$eval: 'default_task_definition'} From 71ab021a087080d51c952e6bf7348db57b561fac Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Mon, 12 Aug 2019 20:17:32 +0200 Subject: [PATCH 37/38] Issue #1200: Add bors badge to README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 830fd1edb44..fce42ee4474 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Task Status](https://github.taskcluster.net/v1/repository/mozilla-mobile/android-components/master/badge.svg)](https://github.taskcluster.net/v1/repository/mozilla-mobile/android-components/master/latest) [![codecov](https://codecov.io/gh/mozilla-mobile/android-components/branch/master/graph/badge.svg)](https://codecov.io/gh/mozilla-mobile/android-components) +[![Bors enabled](https://bors.tech/images/badge_small.svg)](https://app.bors.tech/repositories/19637) _A collection of Android libraries to build browsers or browser-like applications._ From a1f9612a214b0455da51bc3d0f999c0ffb2cda3c Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Mon, 12 Aug 2019 20:34:27 +0200 Subject: [PATCH 38/38] Issue #1200: Add marker to separate checklist from PR text (for bors). --- .github/pull_request_template.md | 4 +++- bors.toml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index dcbe9729c43..3165d98bff9 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,4 +1,6 @@ +--- + ### Pull Request checklist @@ -9,4 +11,4 @@ ### After merge - [ ] **Milestone**: Make sure issues closed by this pull request are added to the [milestone](https://github.com/mozilla-mobile/android-components/milestones) of the version currently in development. -- [ ] **Breaking Changes**: If this is a breaking change, please push a draft PR on [Reference Browser](https://github.com/mozilla-mobile/reference-browser) to address the breaking issues. \ No newline at end of file +- [ ] **Breaking Changes**: If this is a breaking change, please push a draft PR on [Reference Browser](https://github.com/mozilla-mobile/reference-browser) to address the breaking issues. diff --git a/bors.toml b/bors.toml index a4e039ceafc..1bf908949fa 100644 --- a/bors.toml +++ b/bors.toml @@ -10,3 +10,4 @@ name = "MickeyMoz" email = "sebastian@mozilla.com" required_approvals = 1 delete_merged_branches = true +cut_body_after = "---"