Bug 1341458 - Move homepage to chrome_settings_overrides. r=bsilverberg,mixedpuppy
authorMichael Kaply <mozilla@kaply.com>
Tue, 07 Mar 2017 10:31:43 -0600
changeset 395682 1af0390360c1712f4010a3dea4b0ecc17a5c83f8
parent 395681 0bf31f0819dc20a0736803b814d4f88f95609031
child 395683 60ad7833817e68ca7b8267517647ee0bf8b78976
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsilverberg, mixedpuppy
bugs1341458
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1341458 - Move homepage to chrome_settings_overrides. r=bsilverberg,mixedpuppy MozReview-Commit-ID: 5wtaUxXco8z
browser/components/extensions/ext-chrome-settings-overrides.js
browser/components/extensions/extensions-browser.manifest
browser/components/extensions/jar.mn
browser/components/extensions/schemas/chrome_settings_overrides.json
browser/components/extensions/schemas/jar.mn
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_url_overrides_home.js
browser/components/extensions/test/browser/head.js
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-chrome-settings-overrides.js
@@ -0,0 +1,31 @@
+/* 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPreferencesManager",
+                                  "resource://gre/modules/ExtensionPreferencesManager.jsm");
+
+/* eslint-disable mozilla/balanced-listeners */
+extensions.on("manifest_chrome_settings_overrides", (type, directive, extension, manifest) => {
+  if (manifest.chrome_settings_overrides.homepage) {
+    ExtensionPreferencesManager.setSetting(extension, "homepage_override",
+                                           manifest.chrome_settings_overrides.homepage);
+  }
+});
+/* eslint-enable mozilla/balanced-listeners */
+
+ExtensionPreferencesManager.addSetting("homepage_override", {
+  prefNames: [
+    "browser.startup.homepage",
+  ],
+  setCallback(value) {
+    return {
+      "browser.startup.homepage": value,
+    };
+  },
+});
--- a/browser/components/extensions/extensions-browser.manifest
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -1,12 +1,13 @@
 # scripts
 category webextension-scripts bookmarks chrome://browser/content/ext-bookmarks.js
 category webextension-scripts browserAction chrome://browser/content/ext-browserAction.js
 category webextension-scripts browsingData chrome://browser/content/ext-browsingData.js
+category webextension-scripts chrome-settings-overrides chrome://browser/content/ext-chrome-settings-overrides.js
 category webextension-scripts commands chrome://browser/content/ext-commands.js
 category webextension-scripts contextMenus chrome://browser/content/ext-contextMenus.js
 category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
 category webextension-scripts devtools chrome://browser/content/ext-devtools.js
 category webextension-scripts devtools-inspectedWindow chrome://browser/content/ext-devtools-inspectedWindow.js
 category webextension-scripts devtools-network chrome://browser/content/ext-devtools-network.js
 category webextension-scripts devtools-panels chrome://browser/content/ext-devtools-panels.js
 category webextension-scripts history chrome://browser/content/ext-history.js
@@ -27,16 +28,17 @@ category webextension-scripts-devtools d
 category webextension-scripts-addon contextMenus chrome://browser/content/ext-c-contextMenus.js
 category webextension-scripts-addon omnibox chrome://browser/content/ext-c-omnibox.js
 category webextension-scripts-addon tabs chrome://browser/content/ext-c-tabs.js
 
 # schemas
 category webextension-schemas bookmarks chrome://browser/content/schemas/bookmarks.json
 category webextension-schemas browser_action chrome://browser/content/schemas/browser_action.json
 category webextension-schemas browsing_data chrome://browser/content/schemas/browsing_data.json
+category webextension-schemas chrome_settings_overrides chrome://browser/content/schemas/chrome_settings_overrides.json
 category webextension-schemas commands chrome://browser/content/schemas/commands.json
 category webextension-schemas context_menus chrome://browser/content/schemas/context_menus.json
 category webextension-schemas context_menus_internal chrome://browser/content/schemas/context_menus_internal.json
 category webextension-schemas devtools chrome://browser/content/schemas/devtools.json
 category webextension-schemas devtools_inspected_window chrome://browser/content/schemas/devtools_inspected_window.json
 category webextension-schemas devtools_network chrome://browser/content/schemas/devtools_network.json
 category webextension-schemas devtools_panels chrome://browser/content/schemas/devtools_panels.json
 category webextension-schemas history chrome://browser/content/schemas/history.json
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -10,16 +10,17 @@ browser.jar:
 #endif
 #ifdef XP_WIN
     content/browser/extension-win-panel.css
 #endif
     content/browser/extension.svg
     content/browser/ext-bookmarks.js
     content/browser/ext-browserAction.js
     content/browser/ext-browsingData.js
+    content/browser/ext-chrome-settings-overrides.js
     content/browser/ext-commands.js
     content/browser/ext-contextMenus.js
     content/browser/ext-desktop-runtime.js
     content/browser/ext-devtools.js
     content/browser/ext-devtools-inspectedWindow.js
     content/browser/ext-devtools-network.js
     content/browser/ext-devtools-panels.js
     content/browser/ext-history.js
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/schemas/chrome_settings_overrides.json
@@ -0,0 +1,25 @@
+[
+  {
+    "namespace": "manifest",
+    "types": [
+      {
+        "$extend": "WebExtensionManifest",
+        "properties": {
+          "chrome_settings_overrides": {
+            "type": "object",
+            "optional": true,
+            "additionalProperties": { "$ref": "UnrecognizedProperty" },
+            "properties": {
+              "homepage": {
+                "type": "string",
+                "format": "url",
+                "optional": true,
+                "preprocess": "localize"
+              }
+            }
+          }
+        }
+      }
+    ]
+  }
+]
\ No newline at end of file
--- a/browser/components/extensions/schemas/jar.mn
+++ b/browser/components/extensions/schemas/jar.mn
@@ -1,16 +1,17 @@
 # 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/.
 
 browser.jar:
     content/browser/schemas/bookmarks.json
     content/browser/schemas/browser_action.json
     content/browser/schemas/browsing_data.json
+    content/browser/schemas/chrome_settings_overrides.json
     content/browser/schemas/commands.json
     content/browser/schemas/context_menus.json
     content/browser/schemas/context_menus_internal.json
     content/browser/schemas/devtools.json
     content/browser/schemas/devtools_inspected_window.json
     content/browser/schemas/devtools_network.json
     content/browser/schemas/devtools_panels.json
     content/browser/schemas/history.json
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -115,16 +115,17 @@ support-files =
 [browser_ext_tabs_sendMessage.js]
 [browser_ext_tabs_cookieStoreId.js]
 [browser_ext_tabs_update.js]
 [browser_ext_tabs_zoom.js]
 [browser_ext_tabs_update_url.js]
 [browser_ext_themes_icons.js]
 [browser_ext_topwindowid.js]
 [browser_ext_url_overrides_newtab.js]
+[browser_ext_url_overrides_home.js]
 [browser_ext_webRequest.js]
 [browser_ext_webNavigation_frameId0.js]
 [browser_ext_webNavigation_getFrames.js]
 [browser_ext_webNavigation_onCreatedNavigationTarget.js]
 [browser_ext_webNavigation_onCreatedNavigationTarget_window_open.js]
 [browser_ext_webNavigation_urlbar_transitions.js]
 [browser_ext_windows.js]
 [browser_ext_windows_create.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_home.js
@@ -0,0 +1,184 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                  "resource://gre/modules/AddonManager.jsm");
+
+// Named this way so they correspond to the extensions
+const HOME_URI_2 = "http://example.com/";
+const HOME_URI_3 = "http://example.org/";
+const HOME_URI_4 = "http://example.net/";
+
+add_task(function* test_multiple_extensions_overriding_home_page() {
+  let defaultHomePage = Preferences.get("browser.startup.homepage");
+
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_settings_overrides": {}},
+    useAddonManager: "temporary",
+  });
+
+  let ext2 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_settings_overrides": {homepage: HOME_URI_2}},
+    useAddonManager: "temporary",
+  });
+
+  let ext3 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_settings_overrides": {homepage: HOME_URI_3}},
+    useAddonManager: "temporary",
+  });
+
+  let ext4 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_settings_overrides": {homepage: HOME_URI_4}},
+    useAddonManager: "temporary",
+  });
+
+  yield ext1.startup();
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     "Home url should be the default");
+
+  // Because we are expecting the pref to change when we start or unload, we
+  // need to wait on a pref change.  This is because the pref management is
+  // async and can happen after the startup/unload is finished.
+  let prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext2.startup();
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
+     "Home url should be overridden by the second extension.");
+
+  // Because we are unloading an earlier extension, browser.startup.homepage won't change
+  yield ext1.unload();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
+     "Home url should be overridden by the second extension.");
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext3.startup();
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_3),
+     "Home url should be overridden by the third extension.");
+
+  // Because we are unloading an earlier extension, browser.startup.homepage won't change
+  yield ext2.unload();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_3),
+     "Home url should be overridden by the third extension.");
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext4.startup();
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_4),
+     "Home url should be overridden by the third extension.");
+
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext4.unload();
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_3),
+     "Home url should be overridden by the third extension.");
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext3.unload();
+  yield prefPromise;
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     "Home url should be reset to default");
+});
+
+const HOME_URI_1 = "http://example.com/";
+const USER_URI = "http://example.edu/";
+
+add_task(function* test_extension_setting_home_page_back() {
+  let defaultHomePage = Preferences.get("browser.startup.homepage");
+
+  Preferences.set("browser.startup.homepage", USER_URI);
+
+  is(Preferences.get("browser.startup.homepage"), USER_URI,
+     "Home url should be the user set value");
+
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_settings_overrides": {homepage: HOME_URI_1}},
+    useAddonManager: "temporary",
+  });
+
+  // Because we are expecting the pref to change when we start or unload, we
+  // need to wait on a pref change.  This is because the pref management is
+  // async and can happen after the startup/unload is finished.
+  let prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext1.startup();
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
+     "Home url should be overridden by the second extension.");
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext1.unload();
+  yield prefPromise;
+
+  is(Preferences.get("browser.startup.homepage"), USER_URI,
+     "Home url should be the user set value");
+
+  Preferences.reset("browser.startup.homepage");
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     "Home url should be the default");
+});
+
+add_task(function* test_disable() {
+  let defaultHomePage = Preferences.get("browser.startup.homepage");
+
+  const ID = "id@tests.mozilla.org";
+
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      applications: {
+        gecko: {
+          id: ID,
+        },
+      },
+      "chrome_settings_overrides": {
+        homepage: HOME_URI_1,
+      },
+    },
+    useAddonManager: "temporary",
+  });
+
+  let prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext1.startup();
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
+     "Home url should be overridden by the extension.");
+
+  let addon = yield AddonManager.getAddonByID(ID);
+  is(addon.id, ID);
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  addon.userDisabled = true;
+  yield prefPromise;
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     "Home url should be the default");
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  addon.userDisabled = false;
+  yield prefPromise;
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
+     "Home url should be overridden by the extension.");
+
+  prefPromise = promisePrefChangeObserved("browser.startup.homepage");
+  yield ext1.unload();
+  yield prefPromise;
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     "Home url should be the default");
+});
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -11,16 +11,17 @@
  *          openContextMenu closeContextMenu
  *          openExtensionContextMenu closeExtensionContextMenu
  *          openActionContextMenu openSubmenu closeActionContextMenu
  *          openTabContextMenu closeTabContextMenu
  *          imageBuffer imageBufferFromDataURI
  *          getListStyleImage getPanelForNode
  *          awaitExtensionPanel awaitPopupResize
  *          promiseContentDimensions alterContent
+ *          promisePrefChangeObserved
  */
 
 const {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm", {});
 const {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {});
 
 // We run tests under two different configurations, from browser.ini and
 // browser-remote.ini. When running from browser-remote.ini, the tests are
 // copied to the sub-directory "test-oop-extensions", which we detect here, and
@@ -343,8 +344,16 @@ function closePageAction(extension, win 
   if (node) {
     return promisePopupShown(node).then(() => {
       node.hidePopup();
     });
   }
 
   return Promise.resolve();
 }
+
+function promisePrefChangeObserved(pref) {
+  return new Promise((resolve, reject) =>
+    Preferences.observe(pref, function prefObserver() {
+      Preferences.ignore(pref, prefObserver);
+      resolve();
+    }));
+}