Commit acd7943d authored by MozLando's avatar MozLando
Browse files

Merge #5525 #5527

5525: Closes #5433: Add UX flow for unsupported add-ons r=Amejia481,csadilek a=psymoon

This also has partial implementation for allowing `AddonManager.getAddons()` to include unsupported extensions (https://github.com/mozilla-mobile/android-components/issues/5432

)




5527: Issue #4500: Integrate GV API to enable/disable web extensions r=psymoon,Amejia481 a=csadilek

With this we can enable/disable extensions. Had to add a fix to the `WebExtensionToolbar` to not show disabled extensions, and a fix in our sample browser that had the isChecked condition inverted.

Co-authored-by: default avatarSimon Chae <chaesmn@gmail.com>
Co-authored-by: default avatarChristian Sadilek <christian.sadilek@gmail.com>
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
import mozilla.components.concept.engine.utils.EngineVersion
import mozilla.components.concept.engine.webextension.ActionHandler
import mozilla.components.concept.engine.webextension.BrowserAction
import mozilla.components.concept.engine.webextension.EnableSource
import mozilla.components.concept.engine.webextension.WebExtension
import mozilla.components.concept.engine.webextension.WebExtensionDelegate
import mozilla.components.concept.engine.webnotifications.WebNotificationDelegate
@@ -329,6 +330,7 @@ class GeckoEngine(
     */
    override fun enableWebExtension(
        extension: WebExtension,
        source: EnableSource,
        onSuccess: (WebExtension) -> Unit,
        onError: (Throwable) -> Unit
    ) {
@@ -342,6 +344,7 @@ class GeckoEngine(
     */
    override fun disableWebExtension(
        extension: WebExtension,
        source: EnableSource,
        onSuccess: (WebExtension) -> Unit,
        onError: (Throwable) -> Unit
    ) {
+21 −6
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
import mozilla.components.concept.engine.utils.EngineVersion
import mozilla.components.concept.engine.webextension.ActionHandler
import mozilla.components.concept.engine.webextension.BrowserAction
import mozilla.components.concept.engine.webextension.EnableSource
import mozilla.components.concept.engine.webextension.WebExtension
import mozilla.components.concept.engine.webextension.WebExtensionDelegate
import mozilla.components.concept.engine.webnotifications.WebNotificationDelegate
@@ -329,12 +330,19 @@ class GeckoEngine(
     */
    override fun enableWebExtension(
        extension: WebExtension,
        source: EnableSource,
        onSuccess: (WebExtension) -> Unit,
        onError: (Throwable) -> Unit
    ) {
        // TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1599585
        webExtensionDelegate?.onEnabled(extension)
        onSuccess(extension)
        runtime.webExtensionController.enable((extension as GeckoWebExtension).nativeExtension, source.id).then({
            val enabledExtension = GeckoWebExtension(it!!, runtime.webExtensionController)
            webExtensionDelegate?.onEnabled(enabledExtension)
            onSuccess(enabledExtension)
            GeckoResult<Void>()
        }, { throwable ->
            onError(throwable)
            GeckoResult<Void>()
        })
    }

    /**
@@ -342,12 +350,19 @@ class GeckoEngine(
     */
    override fun disableWebExtension(
        extension: WebExtension,
        source: EnableSource,
        onSuccess: (WebExtension) -> Unit,
        onError: (Throwable) -> Unit
    ) {
        // TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1599585
        webExtensionDelegate?.onDisabled(extension)
        onSuccess(extension)
        runtime.webExtensionController.disable((extension as GeckoWebExtension).nativeExtension, source.id).then({
            val disabledExtension = GeckoWebExtension(it!!, runtime.webExtensionController)
            webExtensionDelegate?.onDisabled(disabledExtension)
            onSuccess(disabledExtension)
            GeckoResult<Void>()
        }, { throwable ->
            onError(throwable)
            GeckoResult<Void>()
        })
    }

    /**
+1 −2
Original line number Diff line number Diff line
@@ -247,8 +247,7 @@ class GeckoWebExtension(
    }

    override fun isEnabled(): Boolean {
        // TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1599585
        return true
        return nativeExtension.metaData?.enabled == true
    }
}

+97 −8
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
@@ -892,6 +893,13 @@ class GeckoEngineTest {
    fun `enable web extension successfully`() {
        val runtime = mock<GeckoRuntime>()
        val extensionController: WebExtensionController = mock()

        val bundle = GeckoBundle()
        bundle.putString("webExtensionId", "id")
        bundle.putString("locationURI", "uri")
        val enabledExtension = MockWebExtension(bundle)
        val enableExtensionResult = GeckoResult<GeckoWebExtension>()
        whenever(extensionController.enable(any(), anyInt())).thenReturn(enableExtensionResult)
        whenever(runtime.webExtensionController).thenReturn(extensionController)

        val engine = GeckoEngine(context, runtime = runtime)
@@ -905,24 +913,68 @@ class GeckoEngineTest {
            true,
            true
        )
        var enabledExtension: WebExtension? = null
        var result: WebExtension? = null
        var onErrorCalled = false

        engine.enableWebExtension(
            extension,
            onSuccess = { enabledExtension = it },
            onSuccess = { result = it },
            onError = { onErrorCalled = true }
        )
        verify(webExtensionsDelegate).onEnabled(enabledExtension!!)
        enableExtensionResult.complete(enabledExtension)

        assertFalse(onErrorCalled)
        assertEquals(enabledExtension, extension)
        assertNotNull(result)
        verify(webExtensionsDelegate).onEnabled(result!!)
    }

    @Test
    fun `enable web extension failure`() {
        val runtime = mock<GeckoRuntime>()
        val extensionController: WebExtensionController = mock()

        val enableExtensionResult = GeckoResult<GeckoWebExtension>()
        whenever(extensionController.enable(any(), anyInt())).thenReturn(enableExtensionResult)
        whenever(runtime.webExtensionController).thenReturn(extensionController)

        val engine = GeckoEngine(context, runtime = runtime)
        val webExtensionsDelegate: WebExtensionDelegate = mock()
        engine.registerWebExtensionDelegate(webExtensionsDelegate)

        val extension = mozilla.components.browser.engine.gecko.webextension.GeckoWebExtension(
            "test-webext",
            "resource://android/assets/extensions/test",
            runtime.webExtensionController,
            true,
            true
        )
        var result: WebExtension? = null
        val expected = IOException()
        var throwable: Throwable? = null

        engine.enableWebExtension(
            extension,
            onSuccess = { result = it },
            onError = { throwable = it }
        )
        enableExtensionResult.completeExceptionally(expected)

        assertSame(expected, throwable)
        assertNull(result)
        verify(webExtensionsDelegate, never()).onEnabled(any())
    }

    @Test
    fun `disable web extension successfully`() {
        val runtime = mock<GeckoRuntime>()
        val extensionController: WebExtensionController = mock()

        val bundle = GeckoBundle()
        bundle.putString("webExtensionId", "id")
        bundle.putString("locationURI", "uri")
        val disabledExtension = MockWebExtension(bundle)
        val disableExtensionResult = GeckoResult<GeckoWebExtension>()
        whenever(extensionController.disable(any(), anyInt())).thenReturn(disableExtensionResult)
        whenever(runtime.webExtensionController).thenReturn(extensionController)

        val engine = GeckoEngine(context, runtime = runtime)
@@ -936,18 +988,55 @@ class GeckoEngineTest {
            true,
            true
        )
        var disabledExtension: WebExtension? = null
        var result: WebExtension? = null
        var onErrorCalled = false

        engine.disableWebExtension(
            extension,
            onSuccess = { disabledExtension = it },
            onSuccess = { result = it },
            onError = { onErrorCalled = true }
        )
        verify(webExtensionsDelegate).onDisabled(disabledExtension!!)
        disableExtensionResult.complete(disabledExtension)

        assertFalse(onErrorCalled)
        assertEquals(disabledExtension, extension)
        assertNotNull(result)
        verify(webExtensionsDelegate).onDisabled(result!!)
    }

    @Test
    fun `disable web extension failure`() {
        val runtime = mock<GeckoRuntime>()
        val extensionController: WebExtensionController = mock()

        val disableExtensionResult = GeckoResult<GeckoWebExtension>()
        whenever(extensionController.disable(any(), anyInt())).thenReturn(disableExtensionResult)
        whenever(runtime.webExtensionController).thenReturn(extensionController)

        val engine = GeckoEngine(context, runtime = runtime)
        val webExtensionsDelegate: WebExtensionDelegate = mock()
        engine.registerWebExtensionDelegate(webExtensionsDelegate)

        val extension = mozilla.components.browser.engine.gecko.webextension.GeckoWebExtension(
            "test-webext",
            "resource://android/assets/extensions/test",
            runtime.webExtensionController,
            true,
            true
        )
        var result: WebExtension? = null
        val expected = IOException()
        var throwable: Throwable? = null

        engine.disableWebExtension(
            extension,
            onSuccess = { result = it },
            onError = { throwable = it }
        )
        disableExtensionResult.completeExceptionally(expected)

        assertSame(expected, throwable)
        assertNull(result)
        verify(webExtensionsDelegate, never()).onEnabled(any())
    }

    @Test(expected = RuntimeException::class)
+20 −5
Original line number Diff line number Diff line
@@ -397,10 +397,25 @@ class GeckoWebExtensionTest {
    @Test
    fun `isEnabled depends on native state`() {
        val webExtensionController: WebExtensionController = mock()
        val extension = GeckoWebExtension(
            WebExtension("resource://url", "id", WebExtension.Flags.NONE, webExtensionController),
            webExtensionController
        )
        assertTrue(extension.isEnabled())

        val bundle = GeckoBundle()
        bundle.putString("webExtensionId", "id")
        bundle.putString("locationURI", "uri")
        val nativeExtensionWithoutMetadata = MockWebExtension(bundle)
        val webExtension = GeckoWebExtension(nativeExtensionWithoutMetadata, webExtensionController)
        assertFalse(webExtension.isEnabled())

        val metaDataBundle = GeckoBundle()
        metaDataBundle.putStringArray("disabledFlags", emptyArray())
        bundle.putBundle("metaData", metaDataBundle)
        val nativeEnabledWebExtension = MockWebExtension(bundle)
        val enabledWebExtension = GeckoWebExtension(nativeEnabledWebExtension, webExtensionController)
        assertTrue(enabledWebExtension.isEnabled())

        metaDataBundle.putStringArray("disabledFlags", arrayOf("userDisabled"))
        bundle.putBundle("metaData", metaDataBundle)
        val nativeDisabledWebExtnesion = MockWebExtension(bundle)
        val disabledWebExtension = GeckoWebExtension(nativeDisabledWebExtnesion, webExtensionController)
        assertFalse(disabledWebExtension.isEnabled())
    }
}
Loading