Bug 1373853 - Show extension that is controlling the new tab in preferences r?jaws draft
authorMark Striemer <mstriemer@mozilla.com>
Fri, 15 Sep 2017 21:07:24 -0500
changeset 669295 e9705138a7ffc175ab59b616d23290a7f092d17a
parent 667121 254e42b6acf0b011bd62e815ec57aecca0a7a487
child 732923 4b2e2077a9542091673cbb966044b99a796ecef4
push id81292
push userbmo:mstriemer@mozilla.com
push dateFri, 22 Sep 2017 21:32:45 +0000
reviewersjaws
bugs1373853
milestone57.0a1
Bug 1373853 - Show extension that is controlling the new tab in preferences r?jaws MozReview-Commit-ID: GycnWgmr9kJ
browser/components/preferences/in-content/main.js
browser/components/preferences/in-content/main.xul
browser/components/preferences/in-content/tests/addons/set_newtab.xpi
browser/components/preferences/in-content/tests/browser.ini
browser/components/preferences/in-content/tests/browser_extension_controlled.js
browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
browser/locales/en-US/chrome/browser/preferences/preferences.properties
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1,18 +1,18 @@
 /* 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/. */
 
 /* import-globals-from preferences.js */
 /* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
 /* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
 
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPreferencesManager",
-                                  "resource://gre/modules/ExtensionPreferencesManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
+                                  "resource://gre/modules/ExtensionSettingsStore.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/Downloads.jsm");
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource:///modules/ShellService.jsm");
 Components.utils.import("resource:///modules/TransientPrefs.jsm");
@@ -207,16 +207,27 @@ var gMainPane = {
     this.updatePerformanceSettingsBox({ duringChangeEvent: false });
 
     // set up the "use current page" label-changing listener
     this._updateUseCurrentButton();
     window.addEventListener("focus", this._updateUseCurrentButton.bind(this));
 
     this.updateBrowserStartupLastSession();
 
+    handleControllingExtension("url_overrides", "newTabURL");
+    let newTabObserver = {
+      observe(subject, topic, data) {
+          handleControllingExtension("url_overrides", "newTabURL");
+      },
+    };
+    Services.obs.addObserver(newTabObserver, "newtab-url-changed");
+    window.addEventListener("unload", () => {
+      Services.obs.removeObserver(newTabObserver, "newtab-url-changed");
+    });
+
     if (AppConstants.platform == "win") {
       // Functionality for "Show tabs in taskbar" on Windows 7 and up.
       try {
         let sysInfo = Cc["@mozilla.org/system-info;1"].
           getService(Ci.nsIPropertyBag2);
         let ver = parseFloat(sysInfo.getProperty("version"));
         let showTabsInTaskbar = document.getElementById("showTabsInTaskbar");
         showTabsInTaskbar.hidden = ver < 6.1;
@@ -240,19 +251,21 @@ var gMainPane = {
     }
     setEventListener("useCurrent", "command",
       gMainPane.setHomePageToCurrent);
     setEventListener("useBookmark", "command",
       gMainPane.setHomePageToBookmark);
     setEventListener("restoreDefaultHomePage", "command",
       gMainPane.restoreDefaultHomePage);
     setEventListener("disableHomePageExtension", "command",
-                     gMainPane.makeDisableControllingExtension("homepage_override"));
+                     gMainPane.makeDisableControllingExtension("prefs", "homepage_override"));
     setEventListener("disableContainersExtension", "command",
-                     gMainPane.makeDisableControllingExtension("privacy.containers"));
+                     gMainPane.makeDisableControllingExtension("prefs", "privacy.containers"));
+    setEventListener("disableNewTabExtension", "command",
+                     gMainPane.makeDisableControllingExtension("url_overrides", "newTabURL"));
     setEventListener("chooseLanguage", "command",
       gMainPane.showLanguages);
     setEventListener("translationAttributionImage", "click",
       gMainPane.openTranslationProviderAttribution);
     setEventListener("translateButton", "command",
       gMainPane.showTranslationExceptions);
     setEventListener("font.language.group", "change",
       gMainPane._rebuildFonts);
@@ -484,17 +497,17 @@ var gMainPane = {
   readBrowserContainersCheckbox() {
     const pref = document.getElementById("privacy.userContext.enabled");
     const settings = document.getElementById("browserContainersSettings");
 
     settings.disabled = !pref.value;
     const containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
     const containersCheckbox = document.getElementById("browserContainersCheckbox");
     containersCheckbox.checked = containersEnabled;
-    handleControllingExtension("privacy.containers")
+    handleControllingExtension("prefs", "privacy.containers")
       .then((isControlled) => {
         containersCheckbox.disabled = isControlled;
       });
   },
 
   /**
    * Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
    */
@@ -656,17 +669,17 @@ var gMainPane = {
 
   syncFromHomePref() {
     let homePref = document.getElementById("browser.startup.homepage");
 
     // Set the "Use Current Page(s)" button's text and enabled state.
     this._updateUseCurrentButton();
 
     // This is an async task.
-    handleControllingExtension("homepage_override")
+    handleControllingExtension("prefs", "homepage_override")
       .then((isControlled) => {
         // Disable or enable the inputs based on if this is controlled by an extension.
         document.querySelectorAll("#browserHomePage, .homepage-button")
           .forEach((button) => {
             button.disabled = isControlled;
           });
       });
 
@@ -750,17 +763,17 @@ var gMainPane = {
     let tabs = this._getTabsForHomePage();
 
     if (tabs.length > 1)
       useCurrent.label = useCurrent.getAttribute("label2");
     else
       useCurrent.label = useCurrent.getAttribute("label1");
 
     // If the homepage is controlled by an extension then you can't use this.
-    if (await getControllingExtensionId("homepage_override")) {
+    if (await getControllingExtensionId("prefs", "homepage_override")) {
       useCurrent.disabled = true;
       return;
     }
 
     // In this case, the button's disabled state is set by preferences.xml.
     let prefName = "pref.browser.homepage.disable_button.current_page";
     if (document.getElementById(prefName).locked)
       return;
@@ -798,19 +811,19 @@ var gMainPane = {
   /**
    * Restores the default home page as the user's home page.
    */
   restoreDefaultHomePage() {
     var homePage = document.getElementById("browser.startup.homepage");
     homePage.value = homePage.defaultValue;
   },
 
-  makeDisableControllingExtension(pref) {
+  makeDisableControllingExtension(type, settingName) {
     return async function disableExtension() {
-      let id = await getControllingExtensionId(pref);
+      let id = await getControllingExtensionId(type, settingName);
       let addon = await AddonManager.getAddonByID(id);
       addon.userDisabled = true;
     };
   },
 
   /**
    * Utility function to enable/disable the button specified by aButtonID based
    * on the value of the Boolean preference specified by aPreferenceID.
@@ -2637,36 +2650,38 @@ function getLocalHandlerApp(aFile) {
   localHandlerApp.executable = aFile;
 
   return localHandlerApp;
 }
 
 let extensionControlledContentIds = {
   "privacy.containers": "browserContainersExtensionContent",
   "homepage_override": "browserHomePageExtensionContent",
+  "newTabURL": "browserNewTabExtensionContent",
 };
 
 /**
   * Check if a pref is being managed by an extension.
   */
-function getControllingExtensionId(settingName) {
-  return ExtensionPreferencesManager.getControllingExtensionId(settingName);
+async function getControllingExtensionId(type, settingName) {
+  await ExtensionSettingsStore.initialize();
+  return ExtensionSettingsStore.getTopExtensionId(type, settingName);
 }
 
 function getControllingExtensionEl(settingName) {
   return document.getElementById(extensionControlledContentIds[settingName]);
 }
 
-async function handleControllingExtension(prefName) {
-  let controllingExtensionId = await getControllingExtensionId(prefName);
+async function handleControllingExtension(type, settingName) {
+  let controllingExtensionId = await getControllingExtensionId(type, settingName);
 
   if (controllingExtensionId) {
-    showControllingExtension(prefName, controllingExtensionId);
+    showControllingExtension(settingName, controllingExtensionId);
   } else {
-    hideControllingExtension(prefName);
+    hideControllingExtension(settingName);
   }
 
   return !!controllingExtensionId;
 }
 
 async function showControllingExtension(settingName, extensionId) {
   let extensionControlledContent = getControllingExtensionEl(settingName);
   // Tell the user what extension is controlling the setting.
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -334,26 +334,32 @@
              id="browserStartupHomePage"/>
       <radio label="&startupBlankPage.label;"
              value="0"
              id="browserStartupBlank"/>
       <radio label="&startupPrevSession.label;"
              value="3"
              id="browserStartupLastSession"/>
     </radiogroup>
+    <hbox id="browserNewTabExtensionContent" align="center" hidden="true">
+      <description control="disableNewTabExtension" flex="1" />
+      <button id="disableNewTabExtension"
+              class="extension-controlled-button accessory-button"
+              label="&disableExtension.label;" />
+    </hbox>
   </vbox>
 </groupbox>
 
 <!-- Home Page -->
 <groupbox id="homepageGroup"
           data-category="paneGeneral"
           hidden="true">
   <caption><label>&homepage2.label;</label></caption>
 
-  <hbox id="browserHomePageExtensionContent" align="center">
+  <hbox id="browserHomePageExtensionContent" align="center" hidden="true">
     <description control="disableHomePageExtension" flex="1" />
     <button id="disableHomePageExtension"
             class="extension-controlled-button accessory-button"
             label="&disableExtension.label;" />
   </hbox>
 
   <vbox>
     <textbox id="browserHomePage"
new file mode 100644
index 0000000000000000000000000000000000000000..f11db0b6a8625b2587eb33bd272f35180690a771
GIT binary patch
literal 5210
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
NUQn#EW11`Me*k&^|EvH2
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 support-files =
   head.js
   privacypane_tests_perwindow.js
   site_data_test.html
   addons/set_homepage.xpi
+  addons/set_newtab.xpi
   offline/offline.html
   offline/manifest.appcache
 
 [browser_applications_selection.js]
 skip-if = os == 'linux' # bug 1382057
 [browser_advanced_update.js]
 skip-if = !updater
 [browser_basic_rebuild_fonts_test.js]
@@ -40,16 +41,17 @@ skip-if = os != "win" || (os == "win" &&
 [browser_checkspelling.js]
 [browser_connection.js]
 [browser_connection_bug388287.js]
 [browser_cookies_exceptions.js]
 [browser_defaultbrowser_alwayscheck.js]
 [browser_healthreport.js]
 skip-if = true || !healthreport # Bug 1185403 for the "true"
 [browser_homepages_filter_aboutpreferences.js]
+[browser_extension_controlled.js]
 [browser_layersacceleration.js]
 [browser_masterpassword.js]
 [browser_notifications_do_not_disturb.js]
 [browser_password_management.js]
 [browser_performance.js]
 skip-if = !e10s
 [browser_performance_e10srollout.js]
 skip-if = !e10s
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -0,0 +1,131 @@
+XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
+                                   "@mozilla.org/browser/aboutnewtab-service;1",
+                                   "nsIAboutNewTabService");
+
+const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
+const CHROME_URL_ROOT = TEST_DIR + "/";
+
+function getSupportsFile(path) {
+  let cr = Cc["@mozilla.org/chrome/chrome-registry;1"]
+    .getService(Ci.nsIChromeRegistry);
+  let uri = Services.io.newURI(CHROME_URL_ROOT + path);
+  let fileurl = cr.convertChromeURL(uri);
+  return fileurl.QueryInterface(Ci.nsIFileURL);
+}
+
+function installAddon(xpiName) {
+  let filePath = getSupportsFile(`addons/${xpiName}`).file;
+  return new Promise((resolve, reject) => {
+    AddonManager.getInstallForFile(filePath, install => {
+      if (!install) {
+        throw new Error(`An install was not created for ${filePath}`);
+      }
+      install.addListener({
+        onDownloadFailed: reject,
+        onDownloadCancelled: reject,
+        onInstallFailed: reject,
+        onInstallCancelled: reject,
+        onInstallEnded: resolve
+      });
+      install.install();
+    });
+  });
+}
+
+function waitForMessageChange(messageId, cb) {
+  return new Promise((resolve) => {
+    let target = gBrowser.contentDocument.getElementById(messageId);
+    let observer = new MutationObserver(() => {
+      if (cb(target)) {
+        observer.disconnect();
+        resolve();
+      }
+    });
+    observer.observe(target, { attributes: true, attributeFilter: ["hidden"] });
+  });
+}
+
+function waitForMessageHidden(messageId) {
+  return waitForMessageChange(messageId, target => target.hidden);
+}
+
+function waitForMessageShown(messageId) {
+  return waitForMessageChange(messageId, target => !target.hidden);
+}
+
+add_task(async function testExtensionControlledHomepage() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  let doc = gBrowser.contentDocument;
+  is(gBrowser.currentURI.spec, "about:preferences#general",
+     "#general should be in the URI for about:preferences");
+  let homepagePref = () => Services.prefs.getCharPref("browser.startup.homepage");
+  let originalHomepagePref = homepagePref();
+  let extensionHomepage = "https://developer.mozilla.org/";
+  let controlledContent = doc.getElementById("browserHomePageExtensionContent");
+
+  // The homepage is set to the default and editable.
+  ok(originalHomepagePref != extensionHomepage, "homepage is empty by default");
+  is(doc.getElementById("browserHomePage").disabled, false, "The homepage input is enabled");
+  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+  // Install an extension that will set the homepage.
+  await installAddon("set_homepage.xpi");
+  await waitForMessageShown("browserHomePageExtensionContent");
+
+  // The homepage has been set by the extension, the user is notified and it isn't editable.
+  let controlledLabel = controlledContent.querySelector("description");
+  is(homepagePref(), extensionHomepage, "homepage is set by extension");
+  // There are two spaces before "set_homepage" because it's " <image /> set_homepage".
+  is(controlledLabel.textContent, "An extension,  set_homepage, controls your home page.",
+     "The user is notified that an extension is controlling the homepage");
+  is(controlledContent.hidden, false, "The extension controlled row is hidden");
+  is(doc.getElementById("browserHomePage").disabled, true, "The homepage input is disabled");
+
+  // Disable the extension.
+  doc.getElementById("disableHomePageExtension").click();
+
+  await waitForMessageHidden("browserHomePageExtensionContent");
+
+  is(homepagePref(), originalHomepagePref, "homepage is set back to default");
+  is(doc.getElementById("browserHomePage").disabled, false, "The homepage input is enabled");
+  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function testExtensionControlledNewTab() {
+  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  let doc = gBrowser.contentDocument;
+  is(gBrowser.currentURI.spec, "about:preferences#general",
+     "#general should be in the URI for about:preferences");
+
+  let controlledContent = doc.getElementById("browserNewTabExtensionContent");
+
+  // The new tab is set to the default and message is hidden.
+  ok(!aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab is not set");
+  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+  // Install an extension that will set the new tab page.
+  await installAddon("set_newtab.xpi");
+
+  await waitForMessageShown("browserNewTabExtensionContent");
+
+  // The new tab page has been set by the extension and the user is notified.
+  let controlledLabel = controlledContent.querySelector("description");
+  ok(aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab url is set by extension");
+  // There are two spaces before "set_newtab" because it's " <image /> set_newtab".
+  is(controlledLabel.textContent, "An extension,  set_newtab, controls your New Tab page.",
+     "The user is notified that an extension is controlling the new tab page");
+  is(controlledContent.hidden, false, "The extension controlled row is hidden");
+
+  // Disable the extension.
+  doc.getElementById("disableNewTabExtension").click();
+
+  await waitForMessageHidden("browserNewTabExtensionContent");
+
+  ok(!aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab page is set back to default");
+  is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
--- a/browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
+++ b/browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
@@ -13,99 +13,8 @@ add_task(async function testSetHomepageU
   is(gBrowser.tabs.length, 3, "Three tabs should be open");
   is(Services.prefs.getCharPref("browser.startup.homepage"), "about:blank|about:home",
      "about:blank and about:home should be the only homepages set");
 
   Services.prefs.setCharPref("browser.startup.homepage", oldHomepagePref);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
-
-const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-const CHROME_URL_ROOT = TEST_DIR + "/";
-
-function getSupportsFile(path) {
-  let cr = Cc["@mozilla.org/chrome/chrome-registry;1"]
-    .getService(Ci.nsIChromeRegistry);
-  let uri = Services.io.newURI(CHROME_URL_ROOT + path);
-  let fileurl = cr.convertChromeURL(uri);
-  return fileurl.QueryInterface(Ci.nsIFileURL);
-}
-
-function installAddon() {
-  let filePath = getSupportsFile("addons/set_homepage.xpi").file;
-  return new Promise((resolve, reject) => {
-    AddonManager.getInstallForFile(filePath, install => {
-      if (!install) {
-        throw new Error(`An install was not created for ${filePath}`);
-      }
-      install.addListener({
-        onDownloadFailed: reject,
-        onDownloadCancelled: reject,
-        onInstallFailed: reject,
-        onInstallCancelled: reject,
-        onInstallEnded: resolve
-      });
-      install.install();
-    });
-  });
-}
-
-function waitForMessageChange(cb) {
-  return new Promise((resolve) => {
-    let target = gBrowser.contentDocument.getElementById("browserHomePageExtensionContent");
-    let observer = new MutationObserver(() => {
-      if (cb(target)) {
-        observer.disconnect();
-        resolve();
-      }
-    });
-    observer.observe(target, { attributes: true, attributeFilter: ["hidden"] });
-  });
-}
-
-function waitForMessageHidden() {
-  return waitForMessageChange(target => target.hidden);
-}
-
-function waitForMessageShown() {
-  return waitForMessageChange(target => !target.hidden);
-}
-
-add_task(async function testExtensionControlledHomepage() {
-  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
-  let doc = gBrowser.contentDocument;
-  is(gBrowser.currentURI.spec, "about:preferences#general",
-     "#general should be in the URI for about:preferences");
-  let homepagePref = () => Services.prefs.getCharPref("browser.startup.homepage");
-  let originalHomepagePref = homepagePref();
-  let extensionHomepage = "https://developer.mozilla.org/";
-  let controlledContent = doc.getElementById("browserHomePageExtensionContent");
-
-  // The homepage is set to the default and editable.
-  ok(originalHomepagePref != extensionHomepage, "homepage is empty by default");
-  is(doc.getElementById("browserHomePage").disabled, false, "The homepage input is enabled");
-  is(controlledContent.hidden, true, "The extension controlled row is hidden");
-
-  // Install an extension that will set the homepage.
-  await installAddon();
-  await waitForMessageShown();
-
-  // The homepage has been set by the extension, the user is notified and it isn't editable.
-  let controlledLabel = controlledContent.querySelector("description");
-  is(homepagePref(), extensionHomepage, "homepage is set by extension");
-  // There are two spaces before "set_homepage" because it's " <image /> set_homepage".
-  is(controlledLabel.textContent, "An extension,  set_homepage, controls your home page.",
-     "The user is notified that an extension is controlling the homepage");
-  is(controlledContent.hidden, false, "The extension controlled row is hidden");
-  is(doc.getElementById("browserHomePage").disabled, true, "The homepage input is disabled");
-
-  // Disable the extension.
-  doc.getElementById("disableHomePageExtension").click();
-
-  await waitForMessageHidden();
-
-  is(homepagePref(), originalHomepagePref, "homepage is set back to default");
-  is(doc.getElementById("browserHomePage").disabled, false, "The homepage input is enabled");
-  is(controlledContent.hidden, true, "The extension controlled row is hidden");
-
-  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
-});
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -277,12 +277,16 @@ searchResults.needHelp2=Need help? Visit
 
 # LOCALIZATION NOTE %S is the default value of the `dom.ipc.processCount` pref.
 defaultContentProcessCount=%S (default)
 
 # LOCALIZATION NOTE (extensionControlled.homepage_override):
 # This string is shown to notify the user that their home page is being controlled by an extension.
 extensionControlled.homepage_override = An extension, %S, controls your home page.
 
+# LOCALIZATION NOTE (extensionControlled.newTabURL):
+# This string is shown to notify the user that their new tab page is being controlled by an extension.
+extensionControlled.newTabURL = An extension, %S, controls your New Tab page.
+
 # LOCALIZATION NOTE (extensionControlled.privacy.containers):
 # This string is shown to notify the user that Container Tabs are being enabled by an extension
 # %S is the container addon controlling it
-extensionControlled.privacy.containers = An extension, %S, requires Container Tabs.
\ No newline at end of file
+extensionControlled.privacy.containers = An extension, %S, requires Container Tabs.