summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/androidTest/assets/web_extensions
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/androidTest/assets/web_extensions')
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js140
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.pngbin0 -> 1395 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.pngbin0 -> 1093 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.pngbin0 -> 1074 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js4
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json41
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpibin0 -> 1827 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpibin0 -> 1882 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpibin0 -> 9221 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json20
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js44
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js8
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpibin0 -> 544 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js5
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json26
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js2
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json24
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js29
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json25
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js28
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js6
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html8
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js39
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json25
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js4
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.jsm37
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js88
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json41
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js205
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json174
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js48
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json20
91 files changed, 1651 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js
new file mode 100644
index 0000000000..41c5ed8080
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js
@@ -0,0 +1,14 @@
+"use strict";
+
+module.exports = {
+ env: {
+ webextensions: true,
+ },
+ globals: {
+ ExtensionAPI: true,
+ // available to frameScripts
+ addMessageListener: false,
+ content: false,
+ sendAsyncMessage: false,
+ },
+};
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js
new file mode 100644
index 0000000000..e4e54cc4d2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js
@@ -0,0 +1,140 @@
+const port = browser.runtime.connectNative("browser");
+port.onMessage.addListener(message => {
+ handleMessage(message, null);
+});
+
+browser.runtime.onMessage.addListener((message, sender) => {
+ handleMessage(message, sender.tab.id);
+});
+
+browser.pageAction.onClicked.addListener(tab => {
+ port.postMessage({ method: "onClicked", tabId: tab.id, type: "pageAction" });
+});
+
+browser.browserAction.onClicked.addListener(tab => {
+ port.postMessage({
+ method: "onClicked",
+ tabId: tab.id,
+ type: "browserAction",
+ });
+});
+
+function handlePageActionMessage(message, tabId) {
+ switch (message.action) {
+ case "enable":
+ browser.pageAction.show(tabId);
+ break;
+
+ case "disable":
+ browser.pageAction.hide(tabId);
+ break;
+
+ case "setPopup":
+ browser.pageAction.setPopup({
+ tabId,
+ popup: message.popup,
+ });
+ break;
+
+ case "setTitle":
+ browser.pageAction.setTitle({
+ tabId,
+ title: message.title,
+ });
+ break;
+
+ case "setIcon":
+ browser.pageAction.setIcon({
+ tabId,
+ imageData: message.imageData,
+ path: message.path,
+ });
+ break;
+
+ default:
+ throw new Error(`Page Action does not support ${message.action}`);
+ }
+}
+
+function handleBrowserActionMessage(message, tabId) {
+ switch (message.action) {
+ case "enable":
+ browser.browserAction.enable(tabId);
+ break;
+
+ case "disable":
+ browser.browserAction.disable(tabId);
+ break;
+
+ case "setBadgeText":
+ browser.browserAction.setBadgeText({
+ tabId,
+ text: message.text,
+ });
+ break;
+
+ case "setBadgeTextColor":
+ browser.browserAction.setBadgeTextColor({
+ tabId,
+ color: message.color,
+ });
+ break;
+
+ case "setBadgeBackgroundColor":
+ browser.browserAction.setBadgeBackgroundColor({
+ tabId,
+ color: message.color,
+ });
+ break;
+
+ case "setPopup":
+ browser.browserAction.setPopup({
+ tabId,
+ popup: message.popup,
+ });
+ break;
+
+ case "setTitle":
+ browser.browserAction.setTitle({
+ tabId,
+ title: message.title,
+ });
+ break;
+
+ case "setIcon":
+ browser.browserAction.setIcon({
+ tabId,
+ imageData: message.imageData,
+ path: message.path,
+ });
+ break;
+
+ default:
+ throw new Error(`Browser Action does not support ${message.action}`);
+ }
+}
+
+function handleMessage(message, tabId) {
+ switch (message.type) {
+ case "ping":
+ port.postMessage({ method: "pong" });
+ return;
+
+ case "load":
+ browser.tabs.update(tabId, {
+ url: message.url,
+ });
+ return;
+
+ case "browserAction":
+ handleBrowserActionMessage(message, tabId);
+ return;
+
+ case "pageAction":
+ handlePageActionMessage(message, tabId);
+ return;
+
+ default:
+ throw new Error(`Unsupported message type ${message.type}`);
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.png
new file mode 100644
index 0000000000..dbed714c56
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.png
new file mode 100644
index 0000000000..89863ccec7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.png
new file mode 100644
index 0000000000..aea2c19784
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg
new file mode 100644
index 0000000000..dd1fae7d15
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg
@@ -0,0 +1 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 500 500" height="500px" id="Layer_1" version="1.1" viewBox="0 0 500 500" width="500px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path clip-rule="evenodd" d="M131.889,150.061v63.597h-27.256 c-20.079,0-36.343,16.263-36.343,36.342v181.711c0,20.078,16.264,36.34,36.343,36.34h290.734c20.078,0,36.345-16.262,36.345-36.34 V250c0-20.079-16.267-36.342-36.345-36.342h-27.254v-63.597c0-65.232-52.882-118.111-118.112-118.111 S131.889,84.828,131.889,150.061z M177.317,213.658v-63.597c0-40.157,32.525-72.685,72.683-72.685 c40.158,0,72.685,32.528,72.685,72.685v63.597H177.317z M213.658,313.599c0-20.078,16.263-36.341,36.342-36.341 s36.341,16.263,36.341,36.341c0,12.812-6.634,24.079-16.625,30.529c0,0,3.55,21.446,7.542,46.699 c0,7.538-6.087,13.625-13.629,13.625h-27.258c-7.541,0-13.627-6.087-13.627-13.625l7.542-46.699 C220.294,337.678,213.658,326.41,213.658,313.599z" fill="#010101" fill-rule="evenodd"/></svg> \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js
new file mode 100644
index 0000000000..eaa2467df0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js
@@ -0,0 +1,4 @@
+const port = browser.runtime.connectNative("browser");
+port.onMessage.addListener(message => {
+ browser.runtime.sendMessage(message);
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json
new file mode 100644
index 0000000000..0d0b3978df
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json
@@ -0,0 +1,41 @@
+{
+ "manifest_version": 2,
+ "name": "actions",
+ "version": "1.0",
+ "description": "Defines Page and Browser actions",
+ "applications": {
+ "gecko": {
+ "id": "actions@tests.mozilla.org"
+ }
+ },
+ "browser_action": {
+ "default_title": "Test action default",
+ "theme_icons": [{
+ "light": "button/beasts-32-light.png",
+ "dark": "button/beasts-32.png",
+ "size": 32
+ }]
+ },
+ "page_action": {
+ "default_title": "Test action default",
+ "default_icon": {
+ "19": "button/geo-19.png",
+ "38": "button/geo-38.png"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "content_scripts": [
+ {
+ "matches": ["<all_urls>"],
+ "js": ["content.js"]
+ }
+ ],
+ "permissions": [
+ "tabs",
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html
new file mode 100644
index 0000000000..fd9d0a26fd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <script type="text/javascript" src="test-open-popup-browser-action.js"></script>
+</head>
+<body>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ </body>
+</body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js
new file mode 100644
index 0000000000..cde31235ac
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js
@@ -0,0 +1,7 @@
+window.addEventListener("DOMContentLoaded", init);
+
+function init() {
+ document.body.addEventListener("click", event => {
+ browser.browserAction.openPopup();
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html
new file mode 100644
index 0000000000..bbf5c5d61d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <script type="text/javascript" src="test-open-popup-page-action.js"></script>
+</head>
+<body>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ </body>
+</body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js
new file mode 100644
index 0000000000..f16d96333f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js
@@ -0,0 +1,7 @@
+window.addEventListener("DOMContentLoaded", init);
+
+function init() {
+ document.body.addEventListener("click", event => {
+ browser.pageAction.openPopup();
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html
new file mode 100644
index 0000000000..80fce17886
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <script src="test-popup.js"></script>
+ </head>
+ <body>
+ <h1> HELLO </h1>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js
new file mode 100644
index 0000000000..47271e744c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js
@@ -0,0 +1,3 @@
+window.addEventListener("DOMContentLoaded", () => {
+ window.close();
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpi
new file mode 100644
index 0000000000..19ce0d7f0f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpi
new file mode 100644
index 0000000000..fd395d13df
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpi
new file mode 100644
index 0000000000..1ed97f1047
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg
new file mode 100644
index 0000000000..dd1fae7d15
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg
@@ -0,0 +1 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 500 500" height="500px" id="Layer_1" version="1.1" viewBox="0 0 500 500" width="500px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path clip-rule="evenodd" d="M131.889,150.061v63.597h-27.256 c-20.079,0-36.343,16.263-36.343,36.342v181.711c0,20.078,16.264,36.34,36.343,36.34h290.734c20.078,0,36.345-16.262,36.345-36.34 V250c0-20.079-16.267-36.342-36.345-36.342h-27.254v-63.597c0-65.232-52.882-118.111-118.112-118.111 S131.889,84.828,131.889,150.061z M177.317,213.658v-63.597c0-40.157,32.525-72.685,72.683-72.685 c40.158,0,72.685,32.528,72.685,72.685v63.597H177.317z M213.658,313.599c0-20.078,16.263-36.341,36.342-36.341 s36.341,16.263,36.341,36.341c0,12.812-6.634,24.079-16.625,30.529c0,0,3.55,21.446,7.542,46.699 c0,7.538-6.087,13.625-13.629,13.625h-27.258c-7.541,0-13.627-6.087-13.627-13.625l7.542-46.699 C220.294,337.678,213.658,326.41,213.658,313.599z" fill="#010101" fill-rule="evenodd"/></svg> \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json
new file mode 100644
index 0000000000..75db8fc0aa
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json
@@ -0,0 +1,20 @@
+{
+ "manifest_version": 2,
+ "name": "Borderify",
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "applications": {
+ "gecko": {
+ "id": "borderify@tests.mozilla.org"
+ }
+ },
+ "icons": {
+ "48": "icons/border-48.png"
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js
new file mode 100644
index 0000000000..d0ae54b3dd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js
@@ -0,0 +1,44 @@
+const port = browser.runtime.connectNative("browser");
+
+async function apiCall(message) {
+ const { type, since, removalOptions, dataTypes } = message;
+ switch (type) {
+ case "clear-downloads":
+ await browser.browsingData.removeDownloads({ since });
+ break;
+ case "clear-form-data":
+ await browser.browsingData.removeFormData({ since });
+ break;
+ case "clear-history":
+ await browser.browsingData.removeHistory({ since });
+ break;
+ case "clear-passwords":
+ await browser.browsingData.removePasswords({ since });
+ break;
+ case "clear":
+ await browser.browsingData.remove(removalOptions, dataTypes);
+ break;
+ case "get-settings":
+ return browser.browsingData.settings();
+ }
+ return null;
+}
+
+port.onMessage.addListener(async message => {
+ const { uuid } = message;
+ try {
+ const result = await apiCall(message);
+ port.postMessage({
+ type: "response",
+ result,
+ uuid,
+ });
+ } catch (exception) {
+ const { message } = exception;
+ port.postMessage({
+ type: "error",
+ error: message,
+ uuid,
+ });
+ }
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json
new file mode 100644
index 0000000000..23df4d8338
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "BrowsingData",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "browsing-data-settings@tests.mozilla.org"
+ }
+ },
+ "version": "1.0",
+ "description": "Tests the browsingData API",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["browsingData", "geckoViewAddons", "nativeMessaging"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js
new file mode 100644
index 0000000000..4597e3328b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js
@@ -0,0 +1,8 @@
+browser.browsingData.removeDownloads({ since: 10001 });
+browser.browsingData.removeFormData({ since: 10002 });
+browser.browsingData.removeHistory({ since: 10003 });
+browser.browsingData.removePasswords({ since: 10004 });
+browser.browsingData.remove(
+ { since: 10005 },
+ { downloads: true, cookies: true }
+);
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json
new file mode 100644
index 0000000000..f7af03c25e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "BrowsingData",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "browsing-data@tests.mozilla.org"
+ }
+ },
+ "version": "1.0",
+ "description": "Tests the browsingData API",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["browsingData"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js
new file mode 100644
index 0000000000..68f51ea5d8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js
@@ -0,0 +1,3 @@
+browser.downloads.download({
+ url: "http://localhost:4245/assets/www/images/test.gif",
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json
new file mode 100644
index 0000000000..67adf58933
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "Download",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "download-flags-false@tests.mozilla.org"
+ }
+ },
+ "description": "Downloads a file",
+ "background": {
+ "scripts": ["download.js"]
+ },
+ "permissions": [
+ "downloads"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js
new file mode 100644
index 0000000000..4bb06a5cbb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js
@@ -0,0 +1,16 @@
+browser.downloads.download({
+ url: "http://localhost:4245/assets/www/images/test.gif",
+ filename: "banana.gif",
+ method: "POST",
+ body: "postbody",
+ headers: [
+ {
+ name: "User-Agent",
+ value: "Mozilla Firefox",
+ },
+ ],
+ allowHttpErrors: true,
+ conflictAction: "overwrite",
+ saveAs: true,
+ incognito: true,
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json
new file mode 100644
index 0000000000..70332e226e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "Download",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "download-flags-true@tests.mozilla.org"
+ }
+ },
+ "description": "Downloads a file",
+ "background": {
+ "scripts": ["download.js"]
+ },
+ "permissions": [
+ "downloads"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpi
new file mode 100644
index 0000000000..0e0f549ceb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js
new file mode 100644
index 0000000000..2a49c0d665
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js
@@ -0,0 +1 @@
+console.log("Hi, I'm a dummy.");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json
new file mode 100644
index 0000000000..88a563ec7d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json
@@ -0,0 +1,21 @@
+{
+ "manifest_version": 2,
+ "name": "Dummy",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "dummy@tests.mozilla.org"
+ }
+ },
+ "description": "Doesn't do anything.",
+ "options_ui": {
+ "open_in_tab": true,
+ "page": "options.html"
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["dummy.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json
new file mode 100644
index 0000000000..d8c41e78b4
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json
@@ -0,0 +1,14 @@
+{
+ "manifest_version": 2,
+ "name": "Test messages sent from extensions when restoring",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "extension-page-restoring@tests.mozilla.org"
+ }
+ },
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js
new file mode 100644
index 0000000000..66866bbd37
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js
@@ -0,0 +1,5 @@
+browser.runtime.sendNativeMessage("browser1", "HELLO_FROM_PAGE_1");
+browser.runtime.sendNativeMessage("browser2", "HELLO_FROM_PAGE_2");
+
+const port = browser.runtime.connectNative("browser1");
+port.postMessage("HELLO_FROM_PORT");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html
new file mode 100644
index 0000000000..f87c77a5d2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html><html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <h1>Hello World!</h1>
+ <script src=tab-script.js></script>
+</body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js
new file mode 100644
index 0000000000..43e2b44f96
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js
@@ -0,0 +1,7 @@
+browser.runtime.onMessage.addListener(notify);
+
+function notify(message) {
+ if (message.action == "showTab") {
+ browser.tabs.update({ url: "/tab.html" });
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json
new file mode 100644
index 0000000000..31ce6e022f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json
@@ -0,0 +1,26 @@
+{
+ "manifest_version": 2,
+ "name": "Mozilla Android Components - Tabs Update Test",
+ "version": "1.0",
+ "background": {
+ "scripts": ["background-script.js"]
+ },
+ "applications": {
+ "gecko": {
+ "id": "extension-page-update@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["tabs.js"],
+ "run_at": "document_idle"
+ }
+ ],
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "tabs",
+ "<all_urls>"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js
new file mode 100644
index 0000000000..011f3bb301
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js
@@ -0,0 +1,2 @@
+// Let's test privileged APIs
+browser.runtime.sendNativeMessage("browser", "HELLO_FROM_PAGE");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html
new file mode 100644
index 0000000000..f87c77a5d2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html><html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <h1>Hello World!</h1>
+ <script src=tab-script.js></script>
+</body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js
new file mode 100644
index 0000000000..ef5fbf6ce3
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js
@@ -0,0 +1 @@
+browser.runtime.sendMessage({ action: "showTab" });
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json
new file mode 100644
index 0000000000..aa2b239aef
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json
@@ -0,0 +1,24 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Test messaging between app and web extension",
+ "applications": {
+ "gecko": {
+ "id": "messaging-content@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": [
+ "*://*.example.com/*"
+ ],
+ "js": ["messaging.js"]
+ }
+ ],
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js
new file mode 100644
index 0000000000..1c8323df53
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js
@@ -0,0 +1,29 @@
+// This message should not be handled
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ const response = await browser.runtime.sendNativeMessage(
+ "browser",
+ "testContentBrowserMessage"
+ );
+
+ browser.runtime.sendNativeMessage("browser", `response: ${response}`);
+
+ const port = browser.runtime.connectNative("browser");
+ port.onMessage.addListener(response => {
+ if (response.action === "disconnect") {
+ port.disconnect();
+ return;
+ }
+
+ port.postMessage(`response: ${response.message}`);
+ });
+
+ port.onDisconnect.addListener(() =>
+ browser.runtime.sendNativeMessage("browser", { type: "portDisconnected" })
+ );
+
+ port.postMessage("testContentPortMessage");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json
new file mode 100644
index 0000000000..78605f460b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json
@@ -0,0 +1,25 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Test messaging between app and web extension",
+ "applications": {
+ "gecko": {
+ "id": "messaging-iframe@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": [
+ "*://localhost/*"
+ ],
+ "js": ["messaging.js"],
+ "all_frames": true
+ }
+ ],
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js
new file mode 100644
index 0000000000..eb4ad3d8f9
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js
@@ -0,0 +1,11 @@
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ await browser.runtime.sendNativeMessage(
+ "browser",
+ "testContentBrowserMessage"
+ );
+ browser.runtime.connectNative("browser");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js
new file mode 100644
index 0000000000..20deb53ae7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js
@@ -0,0 +1,28 @@
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ const response = await browser.runtime.sendNativeMessage(
+ "browser",
+ "testBackgroundBrowserMessage"
+ );
+
+ browser.runtime.sendNativeMessage("browser", `response: ${response}`);
+
+ const port = browser.runtime.connectNative("browser");
+ port.onMessage.addListener(response => {
+ if (response.action === "disconnect") {
+ port.disconnect();
+ return;
+ }
+
+ port.postMessage(`response: ${response.message}`);
+ });
+
+ port.onDisconnect.addListener(() =>
+ browser.runtime.sendNativeMessage("browser", { type: "portDisconnected" })
+ );
+
+ port.postMessage("testBackgroundPortMessage");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json
new file mode 100644
index 0000000000..e61380311b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json
@@ -0,0 +1,21 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Test messaging between app and web extension",
+ "icons": {
+ "48": "icons/border-48.png"
+ },
+ "applications": {
+ "gecko": {
+ "id": "messaging@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js
new file mode 100644
index 0000000000..463010d1d5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js
@@ -0,0 +1,6 @@
+browser.notifications.create("cake-notification", {
+ type: "basic",
+ title: "Time for cake!",
+ iconUrl: "http://example.com/img.svg",
+ message: "Something something cake",
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json
new file mode 100644
index 0000000000..69821d8d85
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "Notification test",
+ "version": "1.0",
+ "description": "Send a notification.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "notification@example.com"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "notifications"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js
new file mode 100644
index 0000000000..1872c48d00
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js
@@ -0,0 +1 @@
+browser.runtime.openOptionsPage();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json
new file mode 100644
index 0000000000..380b0657fb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json
@@ -0,0 +1,22 @@
+{
+ "manifest_version": 2,
+ "name": "openOptionsPage-1",
+ "version": "1.0",
+ "description": "Opens options page in a new tab.",
+ "applications": {
+ "gecko": {
+ "id": "openoptionspage1@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs"
+ ],
+ "options_ui": {
+ "page": "options.html",
+ "browser_style": true,
+ "open_in_tab": true
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js
new file mode 100644
index 0000000000..1872c48d00
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js
@@ -0,0 +1 @@
+browser.runtime.openOptionsPage();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json
new file mode 100644
index 0000000000..217034851f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json
@@ -0,0 +1,22 @@
+{
+ "manifest_version": 2,
+ "name": "openOptionsPage-2",
+ "version": "1.0",
+ "description": "Opens options page via delegate.",
+ "applications": {
+ "gecko": {
+ "id": "openoptionspage2@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs"
+ ],
+ "options_ui": {
+ "page": "options.html",
+ "browser_style": true,
+ "open_in_tab": false
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json
new file mode 100644
index 0000000000..89befc953b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 2,
+ "name": "Page History",
+ "version": "1.0",
+ "applications": {
+ "gecko": {
+ "id": "page-history@tests.mozilla.org"
+ }
+ },
+ "description": "Can load a WebExtension Page."
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html
new file mode 100644
index 0000000000..eb16e3b850
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html><html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <h1> Hello, World! </h1>
+</body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js
new file mode 100644
index 0000000000..fdf088a505
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js
@@ -0,0 +1,39 @@
+"use strict";
+
+function setupRedirect(fromUrl, redirectUrl) {
+ browser.webRequest.onBeforeRequest.addListener(
+ details => {
+ console.log(`Extension redirects from ${fromUrl} to ${redirectUrl}`);
+ return { redirectUrl };
+ },
+ { urls: [fromUrl] },
+ ["blocking"]
+ );
+}
+
+// Intercepts all script requests from androidTest/assets/www/trackers.html.
+// Scripts are executed in order of appearance in the page and block the
+// page's "load" event, so the test runner can just wait for the page to
+// have loaded and then check the page content to verify that the requests
+// were intercepted as expected.
+setupRedirect(
+ "http://trackertest.org/tracker.js",
+ "data:text/javascript,document.body.textContent='start'"
+);
+setupRedirect(
+ "https://tracking.example.com/tracker.js",
+ browser.runtime.getURL("web-accessible-script.js")
+);
+setupRedirect(
+ "https://itisatracker.org/tracker.js",
+ `data:text/javascript,document.body.textContent+=',end'`
+);
+
+// Work around bug 1300234 to ensure that the webRequest listener has been
+// registered before we resume the test. API result doesn't matter, we just
+// want to make a roundtrip.
+var listenerReady = browser.webRequest.getSecurityInfo("").catch(() => {});
+
+listenerReady.then(() => {
+ browser.runtime.sendNativeMessage("browser", "setupReadyStartTest");
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json
new file mode 100644
index 0000000000..11ef641ae9
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json
@@ -0,0 +1,25 @@
+{
+ "name": "redirect-to-android-resource",
+ "description": "Redirects script requests from trackers.html to moz-extension:-resource packaged in the APK (resource://android/...)",
+ "manifest_version": 2,
+ "version": "1",
+ "applications": {
+ "gecko": {
+ "id": "redirect-to-android-resource@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "webRequest",
+ "webRequestBlocking",
+ "http://localhost/",
+ "http://trackertest.org/",
+ "https://tracking.example.com/",
+ "https://itisatracker.org/tracker.js"
+ ],
+ "web_accessible_resources": ["web-accessible-script.js"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js
new file mode 100644
index 0000000000..a26c4cc91c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js
@@ -0,0 +1,3 @@
+"use strict";
+
+document.body.textContent += ",extension-was-here";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js
new file mode 100644
index 0000000000..f8ecef0215
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js
@@ -0,0 +1,16 @@
+browser.tabs.onActivated.addListener(async tabChange => {
+ const activeTabs = await browser.tabs.query({ active: true });
+ const currentWindow = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ if (
+ activeTabs.length === 1 &&
+ activeTabs[0].id == tabChange.tabId &&
+ currentWindow.length === 1 &&
+ currentWindow[0].id === tabChange.tabId
+ ) {
+ browser.tabs.remove(tabChange.tabId);
+ }
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json
new file mode 100644
index 0000000000..4a5b79ab32
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json
@@ -0,0 +1,17 @@
+{
+ "applications": {
+ "gecko": {
+ "id": "set-tab-active-2@tests.mozilla.org"
+ }
+ },
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Removes the activated Tab.",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js
new file mode 100644
index 0000000000..f8ecef0215
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js
@@ -0,0 +1,16 @@
+browser.tabs.onActivated.addListener(async tabChange => {
+ const activeTabs = await browser.tabs.query({ active: true });
+ const currentWindow = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ if (
+ activeTabs.length === 1 &&
+ activeTabs[0].id == tabChange.tabId &&
+ currentWindow.length === 1 &&
+ currentWindow[0].id === tabChange.tabId
+ ) {
+ browser.tabs.remove(tabChange.tabId);
+ }
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json
new file mode 100644
index 0000000000..493e6befb0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json
@@ -0,0 +1,17 @@
+{
+ "applications": {
+ "gecko": {
+ "id": "set-tab-active@tests.mozilla.org"
+ }
+ },
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Removes the activated Tab.",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js
new file mode 100644
index 0000000000..835e156b86
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js
@@ -0,0 +1,4 @@
+browser.tabs.create({
+ url: "https://www.mozilla.org/en-US/",
+ cookieStoreId: "1",
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json
new file mode 100644
index 0000000000..995a85a9a0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Creates a tab with a contextual identity.",
+ "applications": {
+ "gecko": {
+ "id": "tabs-create-2@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs",
+ "cookies"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js
new file mode 100644
index 0000000000..a1f55a3a4f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js
@@ -0,0 +1,3 @@
+browser.tabs.create({}).then(tab => {
+ browser.tabs.remove(tab.id);
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json
new file mode 100644
index 0000000000..25f348def8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json
@@ -0,0 +1,16 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Creates and removes a tab.",
+ "applications" : {
+ "gecko": {
+ "id": "tabs-create-remove@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js
new file mode 100644
index 0000000000..6fbd381e61
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js
@@ -0,0 +1 @@
+browser.tabs.create({ url: "https://www.mozilla.org/en-US/" });
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json
new file mode 100644
index 0000000000..af0d40020f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Creates a tab.",
+ "applications": {
+ "gecko": {
+ "id": "tabs-create@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js
new file mode 100644
index 0000000000..c6ec7aee33
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js
@@ -0,0 +1,3 @@
+browser.tabs.query({ url: "*://*/*?tabToClose" }).then(([tab]) => {
+ browser.tabs.remove(tab.id);
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json
new file mode 100644
index 0000000000..bd5c977ba0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Removes an existing tab.",
+ "applications": {
+ "gecko": {
+ "id": "tabs-remove@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "tabs"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.jsm b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.jsm
new file mode 100644
index 0000000000..23d82f2623
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.jsm
@@ -0,0 +1,37 @@
+/* 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/. */
+
+const { GeckoViewActorChild } = ChromeUtils.import(
+ "resource://gre/modules/GeckoViewActorChild.jsm"
+);
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const EXPORTED_SYMBOLS = ["TestSupportChild"];
+
+class TestSupportChild extends GeckoViewActorChild {
+ receiveMessage(aMsg) {
+ debug`receiveMessage: ${aMsg.name}`;
+
+ switch (aMsg.name) {
+ case "FlushApzRepaints":
+ return new Promise(resolve => {
+ const repaintDone = () => {
+ debug`APZ flush done`;
+ Services.obs.removeObserver(repaintDone, "apz-repaints-flushed");
+ resolve();
+ };
+ Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
+ if (this.contentWindow.windowUtils.flushApzRepaints()) {
+ debug`Flushed APZ repaints, waiting for callback...`;
+ } else {
+ debug`Flushing APZ repaints was a no-op, triggering callback directly...`;
+ repaintDone();
+ }
+ });
+ }
+ return null;
+ }
+}
+const { debug } = TestSupportChild.initLogging("GeckoViewTestSupport");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js
new file mode 100644
index 0000000000..d074446039
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js
@@ -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/. */
+
+const port = browser.runtime.connectNative("browser");
+
+const APIS = {
+ AddHistogram({ id, value }) {
+ browser.test.addHistogram(id, value);
+ },
+ Eval({ code }) {
+ // eslint-disable-next-line no-eval
+ return eval(`(async () => {
+ ${code}
+ })()`);
+ },
+ SetScalar({ id, value }) {
+ browser.test.setScalar(id, value);
+ },
+ GetRequestedLocales() {
+ return browser.test.getRequestedLocales();
+ },
+ GetLinkColor({ uri, selector }) {
+ return browser.test.getLinkColor(uri, selector);
+ },
+ GetPidForTab({ tab }) {
+ return browser.test.getPidForTab(tab.id);
+ },
+ GetPrefs({ prefs }) {
+ return browser.test.getPrefs(prefs);
+ },
+ GetActive({ tab }) {
+ return browser.test.getActive(tab.id);
+ },
+ RemoveCertOverride({ host, port }) {
+ browser.test.removeCertOverride(host, port);
+ },
+ RestorePrefs({ oldPrefs }) {
+ return browser.test.restorePrefs(oldPrefs);
+ },
+ SetPrefs({ oldPrefs, newPrefs }) {
+ return browser.test.setPrefs(oldPrefs, newPrefs);
+ },
+ SetResolutionAndScaleTo({ resolution }) {
+ return browser.test.setResolutionAndScaleTo(resolution);
+ },
+ FlushApzRepaints({ tab }) {
+ return browser.test.flushApzRepaints(tab.id);
+ },
+};
+
+port.onMessage.addListener(async message => {
+ const impl = APIS[message.type];
+ apiCall(message, impl);
+});
+
+browser.runtime.onConnect.addListener(contentPort => {
+ contentPort.onMessage.addListener(message => {
+ message.args.tab = contentPort.sender.tab;
+
+ const impl = APIS[message.type];
+ apiCall(message, impl);
+ });
+});
+
+function apiCall(message, impl) {
+ const { id, args } = message;
+ try {
+ sendResponse(id, impl(args));
+ } catch (error) {
+ sendResponse(id, Promise.reject(error));
+ }
+}
+
+function sendResponse(id, response) {
+ Promise.resolve(response).then(
+ value => sendSyncResponse(id, value),
+ reason => sendSyncResponse(id, null, reason)
+ );
+}
+
+function sendSyncResponse(id, response, exception) {
+ port.postMessage({
+ id,
+ response: JSON.stringify(response),
+ exception: exception && exception.toString(),
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json
new file mode 100644
index 0000000000..91f332eb84
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json
@@ -0,0 +1,41 @@
+{
+ "manifest_version": 2,
+ "name": "Test support",
+ "version": "1.0",
+ "description": "Helper script for GeckoView tests",
+ "applications": {
+ "gecko": {
+ "id": "test-support@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": ["<all_urls>"],
+ "js": ["test-support.js"],
+ "run_at": "document_start"
+ }
+ ],
+ "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "experiment_apis": {
+ "test": {
+ "schema": "test-schema.json",
+ "parent": {
+ "scopes": ["addon_parent"],
+ "script": "test-api.js",
+ "events": ["startup"],
+ "paths": [["test"]]
+ }
+ }
+ },
+ "options_ui": {
+ "page": "dummy.html"
+ },
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js
new file mode 100644
index 0000000000..1ed6c40554
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js
@@ -0,0 +1,205 @@
+/* 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/. */
+
+"use strict";
+
+const { E10SUtils } = ChromeUtils.import(
+ "resource://gre/modules/E10SUtils.jsm"
+);
+const { Preferences } = ChromeUtils.import(
+ "resource://gre/modules/Preferences.jsm"
+);
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+function linkColorFrameScript() {
+ addMessageListener("HistoryDelegateTest:GetLinkColor", function onMessage(
+ message
+ ) {
+ const { selector, uri } = message.data;
+
+ if (content.document.documentURI != uri) {
+ return;
+ }
+ const element = content.document.querySelector(selector);
+ if (!element) {
+ sendAsyncMessage("HistoryDelegateTest:GetLinkColor", {
+ ok: false,
+ error: "No element for " + selector,
+ });
+ return;
+ }
+ const color = content.windowUtils.getVisitedDependentComputedStyle(
+ element,
+ "",
+ "color"
+ );
+ sendAsyncMessage("HistoryDelegateTest:GetLinkColor", { ok: true, color });
+ });
+}
+
+function setResolutionAndScaleToFrameScript(resolution) {
+ addMessageListener("PanZoomControllerTest:SetResolutionAndScaleTo", () => {
+ content.window.visualViewport.addEventListener("resize", () => {
+ sendAsyncMessage("PanZoomControllerTest:SetResolutionAndScaleTo");
+ });
+ content.windowUtils.setResolutionAndScaleTo(resolution);
+ });
+}
+
+this.test = class extends ExtensionAPI {
+ onStartup() {
+ ChromeUtils.registerWindowActor("TestSupport", {
+ child: {
+ moduleURI:
+ "resource://android/assets/web_extensions/test-support/TestSupportChild.jsm",
+ },
+ allFrames: true,
+ });
+ }
+
+ onShutdown(isAppShutdown) {
+ if (isAppShutdown) {
+ return;
+ }
+ ChromeUtils.unregisterWindowActor("TestSupport");
+ }
+
+ getAPI(context) {
+ return {
+ test: {
+ /* Set prefs and returns set of saved prefs */
+ async setPrefs(oldPrefs, newPrefs) {
+ // Save old prefs
+ Object.assign(
+ oldPrefs,
+ ...Object.keys(newPrefs)
+ .filter(key => !(key in oldPrefs))
+ .map(key => ({ [key]: Preferences.get(key, null) }))
+ );
+
+ // Set new prefs
+ Preferences.set(newPrefs);
+ return oldPrefs;
+ },
+
+ /* Restore prefs to old value. */
+ async restorePrefs(oldPrefs) {
+ for (const [name, value] of Object.entries(oldPrefs)) {
+ if (value === null) {
+ Preferences.reset(name);
+ } else {
+ Preferences.set(name, value);
+ }
+ }
+ },
+
+ /* Get pref values. */
+ async getPrefs(prefs) {
+ return Preferences.get(prefs);
+ },
+
+ /* Gets link color for a given selector. */
+ async getLinkColor(uri, selector) {
+ const frameScript = `data:text/javascript,(${encodeURI(
+ linkColorFrameScript
+ )}).call(this)`;
+ Services.mm.loadFrameScript(frameScript, true);
+
+ return new Promise((resolve, reject) => {
+ const onMessage = message => {
+ Services.mm.removeMessageListener(
+ "HistoryDelegateTest:GetLinkColor",
+ onMessage
+ );
+ if (message.data.ok) {
+ resolve(message.data.color);
+ } else {
+ reject(message.data.error);
+ }
+ };
+
+ Services.mm.addMessageListener(
+ "HistoryDelegateTest:GetLinkColor",
+ onMessage
+ );
+ Services.mm.broadcastAsyncMessage(
+ "HistoryDelegateTest:GetLinkColor",
+ { uri, selector }
+ );
+ });
+ },
+
+ async getRequestedLocales() {
+ return Services.locale.requestedLocales;
+ },
+
+ async getPidForTab(tabId) {
+ const tab = context.extension.tabManager.get(tabId);
+ const pids = E10SUtils.getBrowserPids(tab.browser);
+ return pids[0];
+ },
+
+ async addHistogram(id, value) {
+ return Services.telemetry.getHistogramById(id).add(value);
+ },
+
+ removeCertOverride(host, port) {
+ const overrideService = Cc[
+ "@mozilla.org/security/certoverride;1"
+ ].getService(Ci.nsICertOverrideService);
+ overrideService.clearValidityOverride(host, port);
+ },
+
+ async setScalar(id, value) {
+ return Services.telemetry.scalarSet(id, value);
+ },
+
+ async setResolutionAndScaleTo(resolution) {
+ const frameScript = `data:text/javascript,(${encodeURI(
+ setResolutionAndScaleToFrameScript
+ )}).call(this, ${resolution})`;
+ Services.mm.loadFrameScript(frameScript, true);
+
+ return new Promise(resolve => {
+ const onMessage = () => {
+ Services.mm.removeMessageListener(
+ "PanZoomControllerTest:SetResolutionAndScaleTo",
+ onMessage
+ );
+ resolve();
+ };
+
+ Services.mm.addMessageListener(
+ "PanZoomControllerTest:SetResolutionAndScaleTo",
+ onMessage
+ );
+ Services.mm.broadcastAsyncMessage(
+ "PanZoomControllerTest:SetResolutionAndScaleTo"
+ );
+ });
+ },
+
+ async getActive(tabId) {
+ const tab = context.extension.tabManager.get(tabId);
+ return tab.browser.docShellIsActive;
+ },
+
+ async flushApzRepaints(tabId) {
+ const tab = context.extension.tabManager.get(tabId);
+ const { browsingContext } = tab.browser;
+
+ // TODO: Note that `waitUntilApzStable` in apz_test_utils.js does
+ // flush APZ repaints in the parent process (i.e. calling
+ // nsIDOMWindowUtils.flushApzRepaints for the parent process) before
+ // flushApzRepaints is called for the target content document, if we
+ // still meet intermittent failures, we might want to do it here as
+ // well.
+ await browsingContext.currentWindowGlobal
+ .getActor("TestSupport")
+ .sendQuery("FlushApzRepaints");
+ },
+ },
+ };
+ }
+};
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json
new file mode 100644
index 0000000000..65ab7d4848
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json
@@ -0,0 +1,174 @@
+[
+ {
+ "namespace": "test",
+ "description": "Additional APIs for test support in GeckoView.",
+ "functions": [
+ {
+ "name": "setPrefs",
+ "type": "function",
+ "async": true,
+ "description": "Set prefs and return a set of saved prefs",
+ "parameters": [
+ {
+ "name": "oldPrefs",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": {"type": "any"}
+ },
+ {
+ "name": "newPrefs",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": {"type": "any"}
+ }
+ ]
+ },
+ {
+ "name": "restorePrefs",
+ "type": "function",
+ "async": true,
+ "description": "Restore prefs to old value",
+ "parameters": [
+ {
+ "type": "any",
+ "name": "oldPrefs"
+ }
+ ]
+ },
+ {
+ "name": "getPrefs",
+ "type": "function",
+ "async": true,
+ "description": "Get pref values.",
+ "parameters": [
+ {
+ "name": "prefs",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ {
+ "name": "getLinkColor",
+ "type": "function",
+ "async": true,
+ "description": "Get resolved color for link for a given page and selector.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "uri"
+ },
+ {
+ "type": "string",
+ "name": "selector"
+ }
+ ]
+ },
+ {
+ "name": "getRequestedLocales",
+ "type": "function",
+ "async": true,
+ "description": "Gets the requested locales.",
+ "parameters": []
+ },
+ {
+ "name": "addHistogram",
+ "type": "function",
+ "async": true,
+ "description": "Add a sample with the given value to the histogram with the given id.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "id"
+ },
+ {
+ "type": "any",
+ "name": "value"
+ }
+ ]
+ },
+ {
+ "name": "removeCertOverride",
+ "type": "function",
+ "async": true,
+ "description": "Revokes SSL certificate overrides for the given host+port.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "host"
+ },
+ {
+ "type": "number",
+ "name": "port"
+ }
+ ]
+ },
+ {
+ "name": "setScalar",
+ "type": "function",
+ "async": true,
+ "description": "Set the given value to the scalar with the given id.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "id"
+ },
+ {
+ "type": "any",
+ "name": "value"
+ }
+ ]
+ },
+ {
+ "name": "setResolutionAndScaleTo",
+ "type": "function",
+ "async": true,
+ "description": "Invokes nsIDOMWindowUtils.setResolutionAndScaleTo.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "resolution"
+ }
+ ]
+ },
+ {
+ "name": "getActive",
+ "type": "function",
+ "async": true,
+ "description": "Returns true if the docShell is active for given tab.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "getPidForTab",
+ "type": "function",
+ "async": true,
+ "description": "Gets the top-level pid belonging to tabId.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "flushApzRepaints",
+ "type": "function",
+ "async": true,
+ "description": "Invokes nsIDOMWindowUtils.flushApzRepaints for the document of the tabId.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ }
+ ]
+ }
+]
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js
new file mode 100644
index 0000000000..c0f073e81d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js
@@ -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/. */
+
+let backgroundPort = null;
+let nativePort = null;
+
+window.addEventListener("pageshow", () => {
+ backgroundPort = browser.runtime.connect();
+ nativePort = browser.runtime.connectNative("browser");
+
+ nativePort.onMessage.addListener(message => {
+ if (message.type) {
+ // This is a session-specific webExtensionApiCall.
+ // Forward to the background script.
+ backgroundPort.postMessage(message);
+ } else if (message.eval) {
+ try {
+ // Using eval here is the whole point of this WebExtension so we can
+ // safely ignore the eslint warning.
+ const response = window.eval(message.eval); // eslint-disable-line no-eval
+ sendResponse(message.id, response);
+ } catch (ex) {
+ sendSyncResponse(message.id, null, ex);
+ }
+ }
+ });
+
+ function sendResponse(id, response, exception) {
+ Promise.resolve(response).then(
+ value => sendSyncResponse(id, value),
+ reason => sendSyncResponse(id, null, reason)
+ );
+ }
+
+ function sendSyncResponse(id, response, exception) {
+ nativePort.postMessage({
+ id,
+ response: JSON.stringify(response),
+ exception: exception && exception.toString(),
+ });
+ }
+});
+
+window.addEventListener("pagehide", () => {
+ backgroundPort.disconnect();
+ nativePort.disconnect();
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json
new file mode 100644
index 0000000000..10515bf76a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update@example.com",
+ "update_url": "https://example.org/tests/junit/update_manifest.json"
+ }
+ },
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+} \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js
new file mode 100644
index 0000000000..3529928d82
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid blue";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json
new file mode 100644
index 0000000000..c820403671
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update@example.com"
+ }
+ },
+ "version": "2.0",
+ "description": "Adds a blue border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+} \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js
new file mode 100644
index 0000000000..a301506ca7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js
@@ -0,0 +1,3 @@
+browser.runtime.onUpdateAvailable.addListener(details => {
+ // Do nothing, this is just here to prevent auto update.
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json
new file mode 100644
index 0000000000..31007b9c3b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json
@@ -0,0 +1,21 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-postpone@example.com",
+ "update_url": "https://example.org/tests/junit/update_manifest.json"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+} \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js
new file mode 100644
index 0000000000..3529928d82
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid blue";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json
new file mode 100644
index 0000000000..92204752dd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-postpone@example.com"
+ }
+ },
+ "version": "2.0",
+ "description": "Adds a blue border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+} \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json
new file mode 100644
index 0000000000..2dedeebc25
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-with-perms@example.com",
+ "update_url": "https://example.org/tests/junit/update_manifest.json"
+ }
+ },
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+} \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js
new file mode 100644
index 0000000000..3529928d82
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid blue";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json
new file mode 100644
index 0000000000..4debd1371c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json
@@ -0,0 +1,20 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-with-perms@example.com"
+ }
+ },
+ "version": "2.0",
+ "description": "Adds a blue border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ],
+ "permissions": [
+ "tabs"
+ ]
+} \ No newline at end of file