Bug 1301315 - Add support for chrome_settings_overrides search engine. r?mixedpuppy draft
authorMichael Kaply <mozilla@kaply.com>
Fri, 02 Jun 2017 15:59:43 -0500
changeset 591077 79fa7790618fe06938b74efe9301e7497b2ae12c
parent 590317 a49112c7a5765802096b3fc298069b9495436107
child 632416 f8948b1be201e4c10f0ec455e8c70b40c1c97fa4
push id62945
push usermozilla@kaply.com
push dateThu, 08 Jun 2017 16:11:19 +0000
reviewersmixedpuppy
bugs1301315
milestone55.0a1
Bug 1301315 - Add support for chrome_settings_overrides search engine. r?mixedpuppy MozReview-Commit-ID: IkpigS3wqs1
browser/components/extensions/ext-chrome-settings-overrides.js
browser/components/extensions/schemas/chrome_settings_overrides.json
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_settings_overrides_search.js
--- a/browser/components/extensions/ext-chrome-settings-overrides.js
+++ b/browser/components/extensions/ext-chrome-settings-overrides.js
@@ -2,25 +2,93 @@
  * 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";
 
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPreferencesManager",
                                   "resource://gre/modules/ExtensionPreferencesManager.jsm");
 
+function searchInitialized() {
+  return new Promise(resolve => {
+    if (Services.search.isInitialized) {
+      resolve();
+    }
+    const SEARCH_SERVICE_TOPIC = "browser-search-service";
+    Services.obs.addObserver(function observer(subject, topic, data) {
+      if (data != "init-complete") {
+        return;
+      }
+
+      Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
+      resolve();
+    }, SEARCH_SERVICE_TOPIC);
+  });
+}
+
 this.chrome_settings_overrides = class extends ExtensionAPI {
-  onManifestEntry(entryName) {
+  async onManifestEntry(entryName) {
     let {extension} = this;
     let {manifest} = extension;
 
     if (manifest.chrome_settings_overrides.homepage) {
       ExtensionPreferencesManager.setSetting(extension, "homepage_override",
                                              manifest.chrome_settings_overrides.homepage);
     }
+    if (manifest.chrome_settings_overrides.search_provider) {
+      await searchInitialized();
+      let searchProvider = manifest.chrome_settings_overrides.search_provider;
+      let isCurrent = false;
+      let index = -1;
+      if (extension.startupReason === "ADDON_UPGRADE") {
+        let engines = Services.search.getEnginesByExtensionID(extension.id);
+        if (engines.length > 0) {
+          // There can be only one engine right now
+          isCurrent = Services.search.currentEngine == engines[0];
+          // Get position of engine and store it
+          index = Services.search.getEngines().indexOf(engines[0]);
+          Services.search.removeEngine(engines[0]);
+        }
+      }
+      try {
+        Services.search.addEngineWithDetails(searchProvider.name.trim(),
+                                             searchProvider.favicon_url,
+                                             searchProvider.keyword, null,
+                                             "GET", searchProvider.search_url,
+                                             extension.id);
+        if (extension.startupReason === "ADDON_UPGRADE") {
+          let engine = Services.search.getEngineByName(searchProvider.name.trim());
+          if (isCurrent) {
+            Services.search.currentEngine = engine;
+          }
+          if (index != -1) {
+            Services.search.moveEngine(engine, index);
+          }
+        }
+      } catch (e) {
+        Components.utils.reportError(e);
+      }
+    }
+  }
+  async onShutdown(reason) {
+    let {extension} = this;
+    if (reason == "ADDON_DISABLE" ||
+        reason == "ADDON_UNINSTALL") {
+      if (extension.manifest.chrome_settings_overrides.search_provider) {
+        await searchInitialized();
+        let engines = Services.search.getEnginesByExtensionID(extension.id);
+        for (let engine of engines) {
+          try {
+            Services.search.removeEngine(engine);
+          } catch (e) {
+            Components.utils.reportError(e);
+          }
+        }
+      }
+    }
   }
 };
 
 ExtensionPreferencesManager.addSetting("homepage_override", {
   prefNames: [
     "browser.startup.homepage",
   ],
   setCallback(value) {
--- a/browser/components/extensions/schemas/chrome_settings_overrides.json
+++ b/browser/components/extensions/schemas/chrome_settings_overrides.json
@@ -10,16 +10,103 @@
             "optional": true,
             "additionalProperties": { "$ref": "UnrecognizedProperty" },
             "properties": {
               "homepage": {
                 "type": "string",
                 "format": "relativeUrl",
                 "optional": true,
                 "preprocess": "localize"
+              },
+             "search_provider": {
+                "type": "object",
+                "optional": true,
+                "additionalProperties": { "$ref": "UnrecognizedProperty" },
+                "properties": {
+                  "name": {
+                    "type": "string",
+                    "preprocess": "localize"
+                  },
+                  "keyword": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize"
+                  },
+                  "search_url": {
+                    "type": "string",
+                    "format": "url",
+                    "pattern": "^https://.*$",
+                    "preprocess": "localize"
+                  },
+                  "favicon_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize"
+                  },
+                  "suggest_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "instant_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "image_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "search_url_post_params": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "instant_url_post_params": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "image_url_post_params": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "alternate_urls": {
+                    "type": "array",
+                    "items": {
+                      "type": "string",
+                      "format": "url",
+                      "preprocess": "localize"
+                    },
+                    "optional": true,
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "prepopulated_id": {
+                    "type": "integer",
+                    "optional": true,
+                    "deprecated": "Unsupported on Firefox."
+                  },
+                  "is_default": {
+                    "type": "boolean",
+                    "optional": true,
+                    "deprecated": "Unsupported on Firefox at this time."
+                  }
+                }
               }
             }
           }
         }
       }
     ]
   }
 ]
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -91,16 +91,17 @@ skip-if = debug || asan # Bug 1354681
 [browser_ext_runtime_openOptionsPage_uninstall.js]
 [browser_ext_runtime_setUninstallURL.js]
 [browser_ext_sessions_forgetClosedTab.js]
 [browser_ext_sessions_forgetClosedWindow.js]
 [browser_ext_sessions_getRecentlyClosed.js]
 [browser_ext_sessions_getRecentlyClosed_private.js]
 [browser_ext_sessions_getRecentlyClosed_tabs.js]
 [browser_ext_sessions_restore.js]
+[browser_ext_settings_overrides_search.js]
 [browser_ext_sidebarAction.js]
 [browser_ext_sidebarAction_browser_style.js]
 [browser_ext_sidebarAction_context.js]
 [browser_ext_sidebarAction_contextMenu.js]
 [browser_ext_sidebarAction_tabs.js]
 [browser_ext_sidebarAction_windows.js]
 [browser_ext_simple.js]
 [browser_ext_tab_runtimeConnect.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_settings_overrides_search.js
@@ -0,0 +1,114 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+add_task(async function test_extension_adding_engine() {
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_settings_overrides": {
+        "search_provider": {
+             "name": "MozSearch",
+             "keyword": "MozSearch",
+             "search_url": "https://example.com/?q={searchTerms}",
+        },
+      },
+    },
+    useAddonManager: "temporary",
+  });
+
+  await ext1.startup();
+
+  let engine = Services.search.getEngineByName("MozSearch");
+  ok(engine, "Engine should exist.");
+
+  await ext1.unload();
+
+  engine = Services.search.getEngineByName("MozSearch");
+  ok(!engine, "Engine should not exist");
+});
+
+add_task(async function test_extension_adding_engine_with_spaces() {
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_settings_overrides": {
+        "search_provider": {
+             "name": "MozSearch     ",
+             "keyword": "MozSearch",
+             "search_url": "https://example.com/?q={searchTerms}",
+        },
+      },
+    },
+    useAddonManager: "temporary",
+  });
+
+  await ext1.startup();
+
+  let engine = Services.search.getEngineByName("MozSearch");
+  ok(engine, "Engine should exist.");
+
+  await ext1.unload();
+
+  engine = Services.search.getEngineByName("MozSearch");
+  ok(!engine, "Engine should not exist");
+});
+
+
+add_task(async function test_upgrade_default_position_engine() {
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_settings_overrides": {
+        "search_provider": {
+             "name": "MozSearch",
+             "keyword": "MozSearch",
+             "search_url": "https://example.com/?q={searchTerms}",
+        },
+      },
+      "applications": {
+        "gecko": {
+           "id": "testengine@mozilla.com",
+        },
+      },
+      "version": "0.1",
+    },
+    useAddonManager: "temporary",
+  });
+
+  let ext2 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_settings_overrides": {
+        "search_provider": {
+             "name": "MozSearch",
+             "keyword": "MozSearch",
+             "search_url": "https://example.com/?q={searchTerms}",
+        },
+      },
+      "applications": {
+        "gecko": {
+           "id": "testengine@mozilla.com",
+        },
+      },
+      "version": "0.2",
+    },
+    useAddonManager: "temporary",
+  });
+
+  await ext1.startup();
+
+  let engine = Services.search.getEngineByName("MozSearch");
+  Services.search.currentEngine = engine;
+  Services.search.moveEngine(engine, 1);
+
+  await ext2.startup();
+
+  engine = Services.search.getEngineByName("MozSearch");
+  is(Services.search.currentEngine, engine, "Default engine should still be MozSearch");
+  is(Services.search.getEngines().indexOf(engine), 1, "Engine is in position 1");
+
+  await ext2.unload();
+  await ext1.unload();
+
+  engine = Services.search.getEngineByName("MozSearch");
+  ok(!engine, "Engine should not exist");
+});
+