Bug 1330567 - Part 1: Fallback to form history if form autofill pref is disabled, r=MattN
authorsteveck-chung <schung@mozilla.com>
Wed, 08 Feb 2017 14:13:59 +0800
changeset 342336 72ecf19a8ec01a113702a479ed28ba3f971017bd
parent 342335 b729a810bfe07f13cb3251160c505f16c519c95d
child 342337 8d52a2b47ce65d739937bcbf654600e95353c31f
push id86837
push usermozilla@noorenberghe.ca
push dateSat, 11 Feb 2017 10:47:01 +0000
treeherdermozilla-inbound@8a2f028e6943 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1330567
milestone54.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 1330567 - Part 1: Fallback to form history if form autofill pref is disabled, r=MattN MozReview-Commit-ID: Aq8NhSkxNId
browser/app/profile/firefox.js
browser/extensions/formautofill/FormAutofillParent.jsm
browser/extensions/formautofill/bootstrap.js
browser/extensions/formautofill/content/FormAutofillContent.js
browser/extensions/formautofill/test/unit/head.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1574,14 +1574,15 @@ pref("browser.crashReports.unsubmittedCh
 #ifdef NIGHTLY_BUILD
 // Enable the (fairly costly) client/server validation on nightly only. The other prefs
 // controlling validation are located in /services/sync/services-sync.js
 pref("services.sync.validation.enabled", true);
 #endif
 
 // Preferences for the form autofill system extension
 pref("browser.formautofill.experimental", false);
+pref("browser.formautofill.enabled", false);
 
 // Enable safebrowsing v4 tables (suffixed by "-proto") update.
 #ifdef NIGHTLY_BUILD
 pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,goog-malware-proto,goog-unwanted-proto,test-malware-simple,test-unwanted-simple");
 pref("urlclassifier.phishTable", "goog-phish-shavar,goog-phish-proto,test-phish-simple");
 #endif
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -26,42 +26,92 @@
  */
 
 /* exported FormAutofillParent */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
+Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ProfileStorage",
                                   "resource://formautofill/ProfileStorage.jsm");
 
 const PROFILE_JSON_FILE_NAME = "autofill-profiles.json";
+const ENABLED_PREF = "browser.formautofill.enabled";
 
-let FormAutofillParent = {
+function FormAutofillParent() {
+}
+
+FormAutofillParent.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
+
   _profileStore: null,
 
+  _enabled: false,
+
   /**
    * Initializes ProfileStorage and registers the message handler.
    */
   init() {
     let storePath =
       OS.Path.join(OS.Constants.Path.profileDir, PROFILE_JSON_FILE_NAME);
 
     this._profileStore = new ProfileStorage(storePath);
     this._profileStore.initialize();
 
-    let mm = Cc["@mozilla.org/globalmessagemanager;1"]
-               .getService(Ci.nsIMessageListenerManager);
-    mm.addMessageListener("FormAutofill:PopulateFieldValues", this);
-    mm.addMessageListener("FormAutofill:GetProfiles", this);
+    // Observing the pref (and storage) changes
+    Services.prefs.addObserver(ENABLED_PREF, this, false);
+    this._enabled = this._getStatus();
+    // Force to trigger the onStatusChanged function for setting listeners properly
+    // while initizlization
+    this._onStatusChanged();
+    Services.mm.addMessageListener("FormAutofill:getEnabledStatus", this);
+  },
+
+  /**
+   * Observe the pref changes and update _enabled cache if status is changed.
+   */
+  observe() {
+    let currentStatus = this._getStatus();
+
+    if (currentStatus !== this._enabled) {
+      this._enabled = currentStatus;
+      this._onStatusChanged();
+    }
+  },
+
+  /**
+   * Add/remove message listener and broadcast the status to frames while the
+   * form autofill status changed.
+   */
+  _onStatusChanged() {
+    if (this._enabled) {
+      Services.mm.addMessageListener("FormAutofill:PopulateFieldValues", this);
+      Services.mm.addMessageListener("FormAutofill:GetProfiles", this);
+    } else {
+      Services.mm.removeMessageListener("FormAutofill:PopulateFieldValues", this);
+      Services.mm.removeMessageListener("FormAutofill:GetProfiles", this);
+    }
+
+    Services.mm.broadcastAsyncMessage("FormAutofill:enabledStatus", this._enabled);
+  },
+
+  /**
+   * Query pref (and storage) status to determine the overall status for
+   * form autofill feature.
+   *
+   * @returns {boolean} status of form autofill feature
+   */
+  _getStatus() {
+    return Services.prefs.getBoolPref(ENABLED_PREF);
   },
 
   /**
    * Handles the message coming from FormAutofillContent.
    *
    * @param   {string} message.name The name of the message.
    * @param   {object} message.data The data of the message.
    * @param   {nsIFrameMessageManager} message.target Caller's message manager.
@@ -69,16 +119,20 @@ let FormAutofillParent = {
   receiveMessage({name, data, target}) {
     switch (name) {
       case "FormAutofill:PopulateFieldValues":
         this._populateFieldValues(data, target);
         break;
       case "FormAutofill:GetProfiles":
         this._getProfiles(data, target);
         break;
+      case "FormAutofill:getEnabledStatus":
+        target.messageManager.sendAsyncMessage("FormAutofill:enabledStatus",
+                                               this._enabled);
+        break;
     }
   },
 
   /**
    * Returns the instance of ProfileStorage. To avoid syncing issues, anyone
    * who needs to access the profile should request the instance by this instead
    * of creating a new one.
    *
@@ -94,20 +148,18 @@ let FormAutofillParent = {
    * @private
    */
   _uninit() {
     if (this._profileStore) {
       this._profileStore._saveImmediately();
       this._profileStore = null;
     }
 
-    let mm = Cc["@mozilla.org/globalmessagemanager;1"]
-               .getService(Ci.nsIMessageListenerManager);
-    mm.removeMessageListener("FormAutofill:PopulateFieldValues", this);
-    mm.removeMessageListener("FormAutofill:GetProfiles", this);
+    Services.mm.removeMessageListener("FormAutofill:PopulateFieldValues", this);
+    Services.mm.removeMessageListener("FormAutofill:GetProfiles", this);
   },
 
   /**
    * Populates the field values and notifies content to fill in. Exception will
    * be thrown if there's no matching profile.
    *
    * @private
    * @param  {string} data.guid
--- a/browser/extensions/formautofill/bootstrap.js
+++ b/browser/extensions/formautofill/bootstrap.js
@@ -16,15 +16,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 function startup() {
   // Besides this pref, we'll need dom.forms.autocomplete.experimental enabled
   // as well to make sure form autocomplete works correctly.
   if (!Services.prefs.getBoolPref("browser.formautofill.experimental")) {
     return;
   }
 
-  FormAutofillParent.init();
+  let parent = new FormAutofillParent();
+  parent.init();
   Services.mm.loadFrameScript("chrome://formautofill/content/FormAutofillContent.js", true);
 }
 
 function shutdown() {}
 function install() {}
 function uninstall() {}
--- a/browser/extensions/formautofill/content/FormAutofillContent.js
+++ b/browser/extensions/formautofill/content/FormAutofillContent.js
@@ -335,19 +335,26 @@ let ProfileAutocomplete = {
 
 /**
  * Handles content's interactions.
  *
  * NOTE: Declares it by "var" to make it accessible in unit tests.
  */
 var FormAutofillContent = {
   init() {
-    ProfileAutocomplete.ensureRegistered();
+    addEventListener("DOMContentLoaded", this);
 
-    addEventListener("DOMContentLoaded", this);
+    addMessageListener("FormAutofill:enabledStatus", (result) => {
+      if (result.data) {
+        ProfileAutocomplete.ensureRegistered();
+      } else {
+        ProfileAutocomplete.ensureUnregistered();
+      }
+    });
+    sendAsyncMessage("FormAutofill:getEnabledStatus");
   },
 
   handleEvent(evt) {
     if (!evt.isTrusted) {
       return;
     }
 
     switch (evt.type) {
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -35,16 +35,18 @@ Components.manager.addBootstrappedManife
 // used, on Windows these might still be pending deletion on the physical file
 // system.  Thus, start from a new base number every time, to make a collision
 // with a file that is still pending deletion highly unlikely.
 let gFileCounter = Math.floor(Math.random() * 1000000);
 
 function loadFormAutofillContent() {
   let facGlobal = {
     addEventListener() {},
+    addMessageListener() {},
+    sendAsyncMessage() {},
   };
   let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
                .getService(Ci.mozIJSSubScriptLoader);
   loader.loadSubScriptWithOptions("chrome://formautofill/content/FormAutofillContent.js", {
     target: facGlobal,
   });
 
   return facGlobal;