Bug 1600742 - Implement WebExtensionController.list. r=snorp,esawin

Differential Revision: https://phabricator.services.mozilla.com/D56793

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Agi Sferro 2019-12-17 23:24:24 +00:00
Родитель f3e3650c45
Коммит dafbe96c98
9 изменённых файлов: 126 добавлений и 11 удалений

Просмотреть файл

@ -1549,6 +1549,7 @@ package org.mozilla.geckoview {
method @UiThread @Nullable public WebExtensionController.PromptDelegate getPromptDelegate();
method @UiThread @Nullable public WebExtensionController.TabDelegate getTabDelegate();
method @NonNull @AnyThread public GeckoResult<WebExtension> install(@NonNull String);
method @AnyThread @NonNull public GeckoResult<List<WebExtension>> list();
method @UiThread public void setPromptDelegate(@Nullable WebExtensionController.PromptDelegate);
method @UiThread public void setTabDelegate(@Nullable WebExtensionController.TabDelegate);
method @NonNull @AnyThread public GeckoResult<Void> uninstall(@NonNull WebExtension);

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1 @@
console.log("Hi, I'm a dummy.");

Просмотреть файл

@ -0,0 +1,17 @@
{
"manifest_version": 2,
"name": "Dummy",
"version": "1.0",
"applications": {
"gecko": {
"id": "dummy@tests.mozilla.org"
}
},
"description": "Doesn't do anything.",
"content_scripts": [
{
"matches": ["*://*.example.com/*"],
"js": ["dummy.js"]
}
]
}

Просмотреть файл

@ -137,9 +137,16 @@ class WebExtensionTest : BaseSessionTest() {
assertThat("Content script should have been applied",
color as String, equalTo("red"))
var list = sessionRule.waitForResult(controller.list())
assertEquals(list.size, 1)
assertEquals(list[0].id, borderify.id)
// Unregister WebExtension and check again
sessionRule.waitForResult(controller.uninstall(borderify))
list = sessionRule.waitForResult(controller.list())
assertEquals(list, emptyList<WebExtension>())
mainSession.reload()
sessionRule.waitForPageStop()
@ -149,6 +156,53 @@ class WebExtensionTest : BaseSessionTest() {
colorAfter as String, equalTo(""))
}
@Test
fun installMultiple() {
// dummy.xpi is not signed, but it could be
sessionRule.setPrefsUntilTestEnd(mapOf(
"xpinstall.signatures.required" to false
))
// First, make sure the list starts empty
var list = sessionRule.waitForResult(controller.list())
assertEquals(list, emptyList<WebExtension>())
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
@AssertCalled(count=2)
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
}
})
// Install in parallell borderify and dummy
val borderifyResult = controller.install(
"resource://android/assets/web_extensions/borderify.xpi")
val dummyResult = controller.install(
"resource://android/assets/web_extensions/dummy.xpi")
val (borderify, dummy) = sessionRule.waitForResult(
GeckoResult.allOf(borderifyResult, dummyResult))
// Make sure the list is updated accordingly
list = sessionRule.waitForResult(controller.list())
assertTrue(list.find { it.id == borderify.id } != null)
assertTrue(list.find { it.id == dummy.id } != null)
assertEquals(list.size, 2)
// Uninstall borderify and verify that it's not in the list anymore
sessionRule.waitForResult(controller.uninstall(borderify))
list = sessionRule.waitForResult(controller.list())
assertEquals(list.size, 1)
assertEquals(list[0].id, dummy.id)
// Uninstall dummy and make sure the list is now empty
sessionRule.waitForResult(controller.uninstall(dummy))
list = sessionRule.waitForResult(controller.list())
assertEquals(list, emptyList<WebExtension>())
}
private fun testInstallError(name: String, expectedError: Int) {
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
@AssertCalled(count = 0)

Просмотреть файл

@ -20,6 +20,7 @@ import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.RuntimeTelemetry;
import org.mozilla.geckoview.SessionTextInput;
import org.mozilla.geckoview.WebExtension;
import org.mozilla.geckoview.WebExtensionController;
import org.mozilla.geckoview.test.util.HttpBin;
import org.mozilla.geckoview.test.util.RuntimeCreator;
import org.mozilla.geckoview.test.util.Environment;
@ -27,6 +28,7 @@ import org.mozilla.geckoview.test.util.UiThreadUtils;
import org.mozilla.geckoview.test.util.Callbacks;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@ -1191,7 +1193,21 @@ public class GeckoSessionTestRule implements TestRule {
}
}
protected void cleanupStatement() {
protected void cleanupExtensions() throws Throwable {
WebExtensionController controller = getRuntime().getWebExtensionController();
List<WebExtension> list = waitForResult(controller.list());
// Uninstall any left-over extensions
for (WebExtension extension : list) {
waitForResult(controller.uninstall(extension));
}
// If an extension was still installed, this test should fail
assertThat("A WebExtension was left installed during this test.",
list.size(), equalTo(0));
}
protected void cleanupStatement() throws Throwable {
mWaitScopeDelegates.clear();
mTestScopeDelegates.clear();
@ -1200,6 +1216,7 @@ public class GeckoSessionTestRule implements TestRule {
}
cleanupSession(mMainSession);
cleanupExtensions();
if (mIgnoreCrash) {
deleteCrashDumps();

Просмотреть файл

@ -51,7 +51,13 @@ public class WebExtensionController {
mData.remove(id);
}
public void put(final String id, final WebExtension extension) {
/**
* Add this extension to the store and update it's current value if it's already present.
*
* @param id the {@link WebExtension} id.
* @param extension the {@link WebExtension} to add to the store.
*/
public void update(final String id, final WebExtension extension) {
mData.put(id, extension);
}
}
@ -392,14 +398,24 @@ public class WebExtensionController {
});
}
// TODO: Bug 1600742 make public
GeckoResult<List<WebExtension>> listInstalled() {
/**
* List installed extensions for this {@link GeckoRuntime}.
*
* The returned list can be used to set delegates on the {@link WebExtension} objects using
* {@link WebExtension#setActionDelegate}, {@link WebExtension#setMessageDelegate}.
*
* @return a {@link GeckoResult} that will resolve when the list of extensions is available.
*/
@AnyThread
@NonNull
public GeckoResult<List<WebExtension>> list() {
final CallbackResult<List<WebExtension>> result = new CallbackResult<List<WebExtension>>() {
@Override
public void sendSuccess(final Object response) {
final GeckoBundle[] bundles = ((GeckoBundle) response)
.getBundleArray("extensions");
final List<WebExtension> list = new ArrayList<>(bundles.length);
for (GeckoBundle bundle : bundles) {
final WebExtension extension = new WebExtension(bundle);
registerWebExtension(extension);
@ -438,7 +454,7 @@ public class WebExtensionController {
/* package */ void registerWebExtension(final WebExtension webExtension) {
webExtension.setDelegateController(new DelegateController(webExtension));
mExtensions.put(webExtension.id, webExtension);
mExtensions.update(webExtension.id, webExtension);
}
/* package */ void handleMessage(final String event, final GeckoBundle message,

Просмотреть файл

@ -29,6 +29,7 @@ exclude: true
- ⚠️ [`WebExtension`][69.5]'s constructor now requires a `WebExtensionController`
instance.
- Added [`GeckoResult.allOf`][73.10] for consuming a list of results.
- Added [`WebExtensionController.list`][73.11] to list all installed extensions.
[73.1]: {{javadoc_uri}}/WebExtensionController.html#install-java.lang.String-
@ -41,6 +42,7 @@ exclude: true
[73.8]: {{javadoc_uri}}/LoginStorage.Delegate.html
[73.9]: {{javadoc_uri}}/GeckoRuntime.html#setLoginStorageDelegate-org.mozilla.geckoview.LoginStorage.Delegate-
[73.10]: {{javadoc_uri}}/GeckoResult.html#allOf-java.util.List-
[73.11]: {{javadoc_uri}}/WebExtensionController.html#list--
## v72
- Added [`GeckoSession.NavigationDelegate.LoadRequest#hasUserGesture`][72.1]. This indicates
@ -508,4 +510,4 @@ exclude: true
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: {{javadoc_uri}}/GeckoResult.html
[api-version]: 919027349db09895822846ea63adacb901b4ab40
[api-version]: 2d592afef93d47a268448aa5fd3289e03bb1f678

Просмотреть файл

@ -240,7 +240,6 @@ class GeckoViewConnection {
}
function exportExtension(aAddon, aPermissions, aSourceURI) {
const { origins, permissions } = aPermissions;
const {
creator,
description,
@ -272,8 +271,8 @@ function exportExtension(aAddon, aPermissions, aSourceURI) {
isEnabled: isActive,
isBuiltIn: isBuiltin,
metaData: {
permissions,
origins,
permissions: aPermissions ? aPermissions.permissions : [],
origins: aPermissions ? aPermissions.origins : [],
description,
version,
creatorName,
@ -642,8 +641,16 @@ var GeckoViewWebExtension = {
}
case "GeckoView:WebExtension:List": {
// TODO
aCallback.onError(`Not implemented`);
try {
const addons = await AddonManager.getAddonsByTypes(["extension"]);
const extensions = addons.map(addon =>
exportExtension(addon, addon.userPermissions, null)
);
aCallback.onSuccess({ extensions });
} catch (ex) {
debug`Failed list ${ex}`;
aCallback.onError(`Unexpected error: ${ex}`);
}
break;
}