Loading components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt +21 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,8 @@ import mozilla.components.browser.engine.gecko.mediaquery.from import mozilla.components.browser.engine.gecko.mediaquery.toGeckoValue import mozilla.components.browser.engine.gecko.webextension.GeckoWebExtension import mozilla.components.browser.engine.gecko.webnotifications.GeckoWebNotificationDelegate import mozilla.components.browser.engine.gecko.webpush.GeckoWebPushDelegate import mozilla.components.browser.engine.gecko.webpush.GeckoWebPushHandler import mozilla.components.concept.engine.Engine import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy Loading @@ -27,6 +29,8 @@ import mozilla.components.concept.engine.utils.EngineVersion import mozilla.components.concept.engine.webextension.WebExtension import mozilla.components.concept.engine.webextension.WebExtensionDelegate import mozilla.components.concept.engine.webnotifications.WebNotificationDelegate import mozilla.components.concept.engine.webpush.WebPushDelegate import mozilla.components.concept.engine.webpush.WebPushHandler import org.json.JSONObject import org.mozilla.geckoview.ContentBlocking import org.mozilla.geckoview.ContentBlockingController Loading @@ -42,6 +46,7 @@ import java.lang.IllegalStateException /** * Gecko-based implementation of Engine interface. */ @Suppress("TooManyFunctions") class GeckoEngine( context: Context, private val defaultSettings: Settings? = null, Loading @@ -53,6 +58,7 @@ class GeckoEngine( private val executor by lazy { executorProvider.invoke() } private val localeUpdater = LocaleSettingUpdater(context, runtime) private var webExtensionDelegate: WebExtensionDelegate? = null private var webPushHandler: WebPushHandler? = null init { runtime.delegate = GeckoRuntime.Delegate { Loading Loading @@ -184,6 +190,21 @@ class GeckoEngine( runtime.webNotificationDelegate = GeckoWebNotificationDelegate(webNotificationDelegate) } /** * See [Engine.registerWebPushDelegate]. */ override fun registerWebPushDelegate( webPushDelegate: WebPushDelegate ): WebPushHandler { runtime.webPushController.setDelegate(GeckoWebPushDelegate(webPushDelegate)) if (webPushHandler == null) { webPushHandler = GeckoWebPushHandler(runtime) } return requireNotNull(webPushHandler) } /** * See [Engine.clearData]. */ Loading components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/webpush/GeckoWebPushDelegate.kt 0 → 100644 +71 −0 Original line number Diff line number Diff line /* 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.engine.gecko.webpush import mozilla.components.concept.engine.webpush.WebPushDelegate import mozilla.components.concept.engine.webpush.WebPushSubscription import org.mozilla.geckoview.GeckoResult import org.mozilla.geckoview.WebPushDelegate as GeckoViewWebPushDelegate import org.mozilla.geckoview.WebPushSubscription as GeckoWebPushSubscription /** * A wrapper for the [WebPushDelegate] to communicate with the Gecko-based delegate. */ internal class GeckoWebPushDelegate(private val delegate: WebPushDelegate) : GeckoViewWebPushDelegate { /** * See [GeckoViewWebPushDelegate.onGetSubscription]. */ override fun onGetSubscription(scope: String): GeckoResult<GeckoWebPushSubscription>? { val result: GeckoResult<GeckoWebPushSubscription> = GeckoResult() delegate.onGetSubscription(scope) { subscription -> result.complete(subscription.toGeckoSubscription()) } return result } /** * See [GeckoViewWebPushDelegate.onSubscribe]. */ override fun onSubscribe(scope: String, appServerKey: ByteArray?): GeckoResult<GeckoWebPushSubscription>? { val result: GeckoResult<GeckoWebPushSubscription> = GeckoResult() delegate.onSubscribe(scope, appServerKey) { subscription -> result.complete(subscription.toGeckoSubscription()) } return result } /** * See [GeckoViewWebPushDelegate.onUnsubscribe]. */ override fun onUnsubscribe(scope: String): GeckoResult<Void>? { val result: GeckoResult<Void> = GeckoResult() delegate.onUnsubscribe(scope) { success -> if (success) { result.complete(null) } else { result.completeExceptionally(IllegalStateException("Un-subscribing from subscription failed.")) } } return result } } /** * A helper extension to convert the subscription data class to the Gecko-based implementation. */ internal fun WebPushSubscription.toGeckoSubscription() = GeckoWebPushSubscription( scope, endpoint, appServerKey, publicKey, authSecret ) components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/webpush/GeckoWebPushHandler.kt 0 → 100644 +32 −0 Original line number Diff line number Diff line /* 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.engine.gecko.webpush import mozilla.components.concept.engine.webpush.WebPushHandler import mozilla.components.concept.engine.webpush.WebPushSubscription import org.mozilla.geckoview.GeckoRuntime /** * Gecko-based implementation of [WebPushHandler], wrapping the * controller object provided by GeckoView. */ internal class GeckoWebPushHandler( private val runtime: GeckoRuntime ) : WebPushHandler { /** * See [WebPushHandler]. */ override fun onPushMessage(subscription: WebPushSubscription, message: ByteArray?) { runtime.webPushController.onPushEvent(subscription.toGeckoSubscription(), message) } /** * See [WebPushHandler]. */ override fun onSubscriptionChanged(subscription: WebPushSubscription) { runtime.webPushController.onSubscriptionChanged(subscription.toGeckoSubscription()) } } components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineTest.kt +27 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import org.mozilla.geckoview.GeckoSession import org.mozilla.geckoview.GeckoWebExecutor import org.mozilla.geckoview.StorageController import org.mozilla.geckoview.WebExtensionController import org.mozilla.geckoview.WebPushController import org.robolectric.Robolectric import java.io.IOException import java.lang.Exception Loading Loading @@ -699,6 +700,32 @@ class GeckoEngineTest { assertTrue(onErrorCalled) } @Test fun `registerWebNotificationDelegate sets delegate`() { val runtime = mock<GeckoRuntime>() val engine = GeckoEngine(context, runtime = runtime) engine.registerWebNotificationDelegate(mock()) verify(runtime).webNotificationDelegate = any() } @Test fun `registerWebPushDelegate sets delegate and returns same handler`() { val runtime = mock<GeckoRuntime>() val controller: WebPushController = mock() val engine = GeckoEngine(context, runtime = runtime) whenever(runtime.webPushController).thenReturn(controller) val handler1 = engine.registerWebPushDelegate(mock()) val handler2 = engine.registerWebPushDelegate(mock()) verify(controller, times(2)).setDelegate(any()) assert(handler1 == handler2) } private fun createDummyLogEntryList(): List<ContentBlockingController.LogEntry> { val addLogEntry = object : ContentBlockingController.LogEntry() {} Loading components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/webpush/GeckoWebPushDelegateTest.kt 0 → 100644 +138 −0 Original line number Diff line number Diff line /* 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.engine.gecko.webpush import androidx.test.ext.junit.runners.AndroidJUnit4 import mozilla.components.concept.engine.webpush.WebPushDelegate import mozilla.components.concept.engine.webpush.WebPushSubscription import mozilla.components.support.test.any import mozilla.components.support.test.eq import mozilla.components.support.test.mock import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.isNull import org.mockito.Mockito.verify import org.mozilla.geckoview.GeckoResult @RunWith(AndroidJUnit4::class) class GeckoWebPushDelegateTest { @Test fun `delegate is always invoked`() { val delegate: WebPushDelegate = mock() val geckoDelegate = GeckoWebPushDelegate(delegate) geckoDelegate.onGetSubscription("test") verify(delegate).onGetSubscription(eq("test"), any()) geckoDelegate.onSubscribe("test", null) verify(delegate).onSubscribe(eq("test"), isNull(), any()) geckoDelegate.onSubscribe("test", "key".toByteArray()) verify(delegate).onSubscribe(eq("test"), eq("key".toByteArray()), any()) geckoDelegate.onUnsubscribe("test") verify(delegate).onUnsubscribe(eq("test"), any()) } @Test fun `onGetSubscription result is completed`() { val subscription = WebPushSubscription( "test", "https://example.com", null, ByteArray(65), ByteArray(16) ) val delegate: WebPushDelegate = object : WebPushDelegate { override fun onGetSubscription( scope: String, onSubscription: (WebPushSubscription) -> Unit ) { onSubscription(subscription) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onGetSubscription("test") result?.accept { sub -> assert(sub!!.scope == subscription.scope) } } @Test fun `onSubscribe result is completed`() { val subscription = WebPushSubscription( "test", "https://example.com", null, ByteArray(65), ByteArray(16) ) val delegate: WebPushDelegate = object : WebPushDelegate { override fun onSubscribe( scope: String, serverKey: ByteArray?, onSubscribe: (WebPushSubscription) -> Unit ) { onSubscribe(subscription) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onSubscribe("test", null) result?.accept { sub -> assert(sub!!.scope == subscription.scope) assertNull(sub.appServerKey) } } @Test fun `onUnsubscribe result is completed successfully`() { val delegate: WebPushDelegate = object : WebPushDelegate { override fun onUnsubscribe( scope: String, onUnsubscribe: (Boolean) -> Unit ) { onUnsubscribe(true) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onUnsubscribe("test") result?.accept { sub -> assertNull(sub) } } @Test fun `onUnsubscribe result receives throwable when unsuccessful`() { val delegate: WebPushDelegate = object : WebPushDelegate { override fun onUnsubscribe( scope: String, onUnsubscribe: (Boolean) -> Unit ) { onUnsubscribe(false) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onUnsubscribe("test") result?.exceptionally<Void> { ex -> assert(ex.toString().contains("Un-subscribing from subscription failed")) GeckoResult.fromValue(null) } } } Loading
components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt +21 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,8 @@ import mozilla.components.browser.engine.gecko.mediaquery.from import mozilla.components.browser.engine.gecko.mediaquery.toGeckoValue import mozilla.components.browser.engine.gecko.webextension.GeckoWebExtension import mozilla.components.browser.engine.gecko.webnotifications.GeckoWebNotificationDelegate import mozilla.components.browser.engine.gecko.webpush.GeckoWebPushDelegate import mozilla.components.browser.engine.gecko.webpush.GeckoWebPushHandler import mozilla.components.concept.engine.Engine import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy Loading @@ -27,6 +29,8 @@ import mozilla.components.concept.engine.utils.EngineVersion import mozilla.components.concept.engine.webextension.WebExtension import mozilla.components.concept.engine.webextension.WebExtensionDelegate import mozilla.components.concept.engine.webnotifications.WebNotificationDelegate import mozilla.components.concept.engine.webpush.WebPushDelegate import mozilla.components.concept.engine.webpush.WebPushHandler import org.json.JSONObject import org.mozilla.geckoview.ContentBlocking import org.mozilla.geckoview.ContentBlockingController Loading @@ -42,6 +46,7 @@ import java.lang.IllegalStateException /** * Gecko-based implementation of Engine interface. */ @Suppress("TooManyFunctions") class GeckoEngine( context: Context, private val defaultSettings: Settings? = null, Loading @@ -53,6 +58,7 @@ class GeckoEngine( private val executor by lazy { executorProvider.invoke() } private val localeUpdater = LocaleSettingUpdater(context, runtime) private var webExtensionDelegate: WebExtensionDelegate? = null private var webPushHandler: WebPushHandler? = null init { runtime.delegate = GeckoRuntime.Delegate { Loading Loading @@ -184,6 +190,21 @@ class GeckoEngine( runtime.webNotificationDelegate = GeckoWebNotificationDelegate(webNotificationDelegate) } /** * See [Engine.registerWebPushDelegate]. */ override fun registerWebPushDelegate( webPushDelegate: WebPushDelegate ): WebPushHandler { runtime.webPushController.setDelegate(GeckoWebPushDelegate(webPushDelegate)) if (webPushHandler == null) { webPushHandler = GeckoWebPushHandler(runtime) } return requireNotNull(webPushHandler) } /** * See [Engine.clearData]. */ Loading
components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/webpush/GeckoWebPushDelegate.kt 0 → 100644 +71 −0 Original line number Diff line number Diff line /* 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.engine.gecko.webpush import mozilla.components.concept.engine.webpush.WebPushDelegate import mozilla.components.concept.engine.webpush.WebPushSubscription import org.mozilla.geckoview.GeckoResult import org.mozilla.geckoview.WebPushDelegate as GeckoViewWebPushDelegate import org.mozilla.geckoview.WebPushSubscription as GeckoWebPushSubscription /** * A wrapper for the [WebPushDelegate] to communicate with the Gecko-based delegate. */ internal class GeckoWebPushDelegate(private val delegate: WebPushDelegate) : GeckoViewWebPushDelegate { /** * See [GeckoViewWebPushDelegate.onGetSubscription]. */ override fun onGetSubscription(scope: String): GeckoResult<GeckoWebPushSubscription>? { val result: GeckoResult<GeckoWebPushSubscription> = GeckoResult() delegate.onGetSubscription(scope) { subscription -> result.complete(subscription.toGeckoSubscription()) } return result } /** * See [GeckoViewWebPushDelegate.onSubscribe]. */ override fun onSubscribe(scope: String, appServerKey: ByteArray?): GeckoResult<GeckoWebPushSubscription>? { val result: GeckoResult<GeckoWebPushSubscription> = GeckoResult() delegate.onSubscribe(scope, appServerKey) { subscription -> result.complete(subscription.toGeckoSubscription()) } return result } /** * See [GeckoViewWebPushDelegate.onUnsubscribe]. */ override fun onUnsubscribe(scope: String): GeckoResult<Void>? { val result: GeckoResult<Void> = GeckoResult() delegate.onUnsubscribe(scope) { success -> if (success) { result.complete(null) } else { result.completeExceptionally(IllegalStateException("Un-subscribing from subscription failed.")) } } return result } } /** * A helper extension to convert the subscription data class to the Gecko-based implementation. */ internal fun WebPushSubscription.toGeckoSubscription() = GeckoWebPushSubscription( scope, endpoint, appServerKey, publicKey, authSecret )
components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/webpush/GeckoWebPushHandler.kt 0 → 100644 +32 −0 Original line number Diff line number Diff line /* 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.engine.gecko.webpush import mozilla.components.concept.engine.webpush.WebPushHandler import mozilla.components.concept.engine.webpush.WebPushSubscription import org.mozilla.geckoview.GeckoRuntime /** * Gecko-based implementation of [WebPushHandler], wrapping the * controller object provided by GeckoView. */ internal class GeckoWebPushHandler( private val runtime: GeckoRuntime ) : WebPushHandler { /** * See [WebPushHandler]. */ override fun onPushMessage(subscription: WebPushSubscription, message: ByteArray?) { runtime.webPushController.onPushEvent(subscription.toGeckoSubscription(), message) } /** * See [WebPushHandler]. */ override fun onSubscriptionChanged(subscription: WebPushSubscription) { runtime.webPushController.onSubscriptionChanged(subscription.toGeckoSubscription()) } }
components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineTest.kt +27 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import org.mozilla.geckoview.GeckoSession import org.mozilla.geckoview.GeckoWebExecutor import org.mozilla.geckoview.StorageController import org.mozilla.geckoview.WebExtensionController import org.mozilla.geckoview.WebPushController import org.robolectric.Robolectric import java.io.IOException import java.lang.Exception Loading Loading @@ -699,6 +700,32 @@ class GeckoEngineTest { assertTrue(onErrorCalled) } @Test fun `registerWebNotificationDelegate sets delegate`() { val runtime = mock<GeckoRuntime>() val engine = GeckoEngine(context, runtime = runtime) engine.registerWebNotificationDelegate(mock()) verify(runtime).webNotificationDelegate = any() } @Test fun `registerWebPushDelegate sets delegate and returns same handler`() { val runtime = mock<GeckoRuntime>() val controller: WebPushController = mock() val engine = GeckoEngine(context, runtime = runtime) whenever(runtime.webPushController).thenReturn(controller) val handler1 = engine.registerWebPushDelegate(mock()) val handler2 = engine.registerWebPushDelegate(mock()) verify(controller, times(2)).setDelegate(any()) assert(handler1 == handler2) } private fun createDummyLogEntryList(): List<ContentBlockingController.LogEntry> { val addLogEntry = object : ContentBlockingController.LogEntry() {} Loading
components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/webpush/GeckoWebPushDelegateTest.kt 0 → 100644 +138 −0 Original line number Diff line number Diff line /* 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.engine.gecko.webpush import androidx.test.ext.junit.runners.AndroidJUnit4 import mozilla.components.concept.engine.webpush.WebPushDelegate import mozilla.components.concept.engine.webpush.WebPushSubscription import mozilla.components.support.test.any import mozilla.components.support.test.eq import mozilla.components.support.test.mock import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.isNull import org.mockito.Mockito.verify import org.mozilla.geckoview.GeckoResult @RunWith(AndroidJUnit4::class) class GeckoWebPushDelegateTest { @Test fun `delegate is always invoked`() { val delegate: WebPushDelegate = mock() val geckoDelegate = GeckoWebPushDelegate(delegate) geckoDelegate.onGetSubscription("test") verify(delegate).onGetSubscription(eq("test"), any()) geckoDelegate.onSubscribe("test", null) verify(delegate).onSubscribe(eq("test"), isNull(), any()) geckoDelegate.onSubscribe("test", "key".toByteArray()) verify(delegate).onSubscribe(eq("test"), eq("key".toByteArray()), any()) geckoDelegate.onUnsubscribe("test") verify(delegate).onUnsubscribe(eq("test"), any()) } @Test fun `onGetSubscription result is completed`() { val subscription = WebPushSubscription( "test", "https://example.com", null, ByteArray(65), ByteArray(16) ) val delegate: WebPushDelegate = object : WebPushDelegate { override fun onGetSubscription( scope: String, onSubscription: (WebPushSubscription) -> Unit ) { onSubscription(subscription) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onGetSubscription("test") result?.accept { sub -> assert(sub!!.scope == subscription.scope) } } @Test fun `onSubscribe result is completed`() { val subscription = WebPushSubscription( "test", "https://example.com", null, ByteArray(65), ByteArray(16) ) val delegate: WebPushDelegate = object : WebPushDelegate { override fun onSubscribe( scope: String, serverKey: ByteArray?, onSubscribe: (WebPushSubscription) -> Unit ) { onSubscribe(subscription) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onSubscribe("test", null) result?.accept { sub -> assert(sub!!.scope == subscription.scope) assertNull(sub.appServerKey) } } @Test fun `onUnsubscribe result is completed successfully`() { val delegate: WebPushDelegate = object : WebPushDelegate { override fun onUnsubscribe( scope: String, onUnsubscribe: (Boolean) -> Unit ) { onUnsubscribe(true) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onUnsubscribe("test") result?.accept { sub -> assertNull(sub) } } @Test fun `onUnsubscribe result receives throwable when unsuccessful`() { val delegate: WebPushDelegate = object : WebPushDelegate { override fun onUnsubscribe( scope: String, onUnsubscribe: (Boolean) -> Unit ) { onUnsubscribe(false) } } val geckoDelegate = GeckoWebPushDelegate(delegate) val result = geckoDelegate.onUnsubscribe("test") result?.exceptionally<Void> { ex -> assert(ex.toString().contains("Un-subscribing from subscription failed")) GeckoResult.fromValue(null) } } }