Bug 1400243 - 1. Use universal DoorHanger in LoginManagerPrompter; r?esawin draft
authorJim Chen <nchen@mozilla.com>
Tue, 19 Sep 2017 00:59:24 -0400
changeset 666754 86def6799a4173bbda6be8a391f0774ca004a8f0
parent 666753 c61e65416da03b46ebb0c2803f455c61160255d9
child 666755 6358469d8223065da1c860d0b9941651911a97d9
push id80491
push userbmo:nchen@mozilla.com
push dateTue, 19 Sep 2017 04:59:49 +0000
reviewersesawin
bugs1400243
milestone57.0a1
Bug 1400243 - 1. Use universal DoorHanger in LoginManagerPrompter; r?esawin Use the universal DoorHanger API from Prompt.jsm to show the login doorhanger from any window. Also, refactor parts of LoginManagerPrompter to use Services.jsm if possible. MozReview-Commit-ID: 3cnzeT0RNgR
mobile/android/components/LoginManagerPrompter.js
--- a/mobile/android/components/LoginManagerPrompter.js
+++ b/mobile/android/components/LoginManagerPrompter.js
@@ -3,17 +3,21 @@
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+  DoorHanger: "resource://gre/modules/Prompt.jsm",
+  Services: "resource://gre/modules/Services.jsm",
+});
 
 /* Constants for password prompt telemetry.
 * Mirrored in nsLoginManagerPrompter.js */
 const PROMPT_DISPLAYED = 0;
 
 const PROMPT_ADD = 1;
 const PROMPT_NOTNOW = 2;
 const PROMPT_NEVER = 3;
@@ -35,32 +39,16 @@ function LoginManagerPrompter() {
 LoginManagerPrompter.prototype = {
   classID: Components.ID("97d12931-abe2-11df-94e2-0800200c9a66"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsILoginManagerPrompter]),
 
   _factory: null,
   _window: null,
   _debug: false, // mirrors signon.debug
 
-  __pwmgr: null, // Password Manager service
-  get _pwmgr() {
-    if (!this.__pwmgr)
-      this.__pwmgr = Cc["@mozilla.org/login-manager;1"].
-                     getService(Ci.nsILoginManager);
-    return this.__pwmgr;
-  },
-
-  __promptService: null, // Prompt service for user interaction
-  get _promptService() {
-    if (!this.__promptService)
-      this.__promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
-                             getService(Ci.nsIPromptService2);
-    return this.__promptService;
-  },
-
   __strBundle: null, // String bundle for L10N
   get _strBundle() {
     if (!this.__strBundle) {
       let bunService = Cc["@mozilla.org/intl/stringbundle;1"].
                        getService(Ci.nsIStringBundleService);
       this.__strBundle = {
         pwmgr: bunService.createBundle("chrome://browser/locale/passwordmgr.properties"),
         brand: bunService.createBundle("chrome://branding/locale/brand.properties")
@@ -100,17 +88,17 @@ LoginManagerPrompter.prototype = {
 
   /* ---------- nsILoginManagerPrompter prompts ---------- */
 
   /*
    * init
    *
    */
   init: function(aWindow, aFactory) {
-    this._chromeWindow = this._getChromeWindow(aWindow).wrappedJSObject;
+    this._window = aWindow;
     this._factory = aFactory || null;
     this._browser = null;
 
     var prefBranch = Services.prefs.getBranch("signon.");
     this._debug = prefBranch.getBoolPref("debug");
     this.log("===== initialized =====");
   },
 
@@ -141,18 +129,16 @@ LoginManagerPrompter.prototype = {
    * @param aButtons
    *        Buttons to display with the doorhanger
    * @param aUsername
    *        Username string used in creating a doorhanger action
    * @param aPassword
    *        Password string used in creating a doorhanger action
    */
   _showLoginNotification: function(aBody, aButtons, aUsername, aPassword) {
-    let tabID = this._chromeWindow.BrowserApp.getTabForBrowser(this._browser).id;
-
     let actionText = {
       text: aUsername,
       type: "EDIT",
       bundle: { username: aUsername,
       password: aPassword }
     };
 
     // The page we're going to hasn't loaded yet, so we want to persist
@@ -163,19 +149,18 @@ LoginManagerPrompter.prototype = {
     // heuristically determine when to ignore such location changes, so
     // we'll try ignoring location changes based on a time interval.
     let options = {
       persistWhileVisible: true,
       timeout: Date.now() + 10000,
       actionText: actionText
     }
 
-    var nativeWindow = this._getNativeWindow();
-    if (nativeWindow)
-      nativeWindow.doorhanger.show(aBody, "password", aButtons, tabID, options, "LOGIN");
+    let win = (this._browser && this._browser.contentWindow) || this._window;
+    DoorHanger.show(win, aBody, "password", aButtons, options, "LOGIN");
   },
 
   /*
    * _showSaveLoginNotification
    *
    * Displays a notification doorhanger (rather than a popup), to allow the user to
    * save the specified login. This allows the user to see the results of
    * their login, and only save a login which they know worked.
@@ -183,19 +168,19 @@ LoginManagerPrompter.prototype = {
    */
   _showSaveLoginNotification: function(aLogin) {
     let brandShortName = this._strBundle.brand.GetStringFromName("brandShortName");
     let notificationText  = this._getLocalizedString("saveLogin", [brandShortName]);
 
     let username = aLogin.username ? this._sanitizeUsername(aLogin.username) : "";
 
     // The callbacks in |buttons| have a closure to access the variables
-    // in scope here; set one to |this._pwmgr| so we can get back to pwmgr
+    // in scope here; set one to |Services.logins| so we can get back to pwmgr
     // without a getService() call.
-    var pwmgr = this._pwmgr;
+    var pwmgr = Services.logins;
     let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_REMEMBER_ACTION");
 
     var buttons = [
       {
         label: this._getLocalizedString("neverButton"),
         callback: function() {
           promptHistogram.add(PROMPT_NEVER);
           pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
@@ -243,19 +228,16 @@ LoginManagerPrompter.prototype = {
     var notificationText;
     if (aOldLogin.username) {
       let displayUser = this._sanitizeUsername(aOldLogin.username);
       notificationText  = this._getLocalizedString("updatePassword", [displayUser]);
     } else {
       notificationText  = this._getLocalizedString("updatePasswordNoUser");
     }
 
-    // The callbacks in |buttons| have a closure to access the variables
-    // in scope here; set one to |this._pwmgr| so we can get back to pwmgr
-    // without a getService() call.
     var self = this;
     let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_UPDATE_ACTION");
 
     var buttons = [
       {
         label: this._getLocalizedString("dontUpdateButton"),
         callback:  function() {
           promptHistogram.add(PROMPT_NOTNOW);
@@ -295,17 +277,17 @@ LoginManagerPrompter.prototype = {
 
     var usernames = logins.map(l => l.username);
     var dialogText  = this._getLocalizedString("userSelectText2");
     var dialogTitle = this._getLocalizedString("passwordChangeTitle");
     var selectedIndex = { value: null };
 
     // If user selects ok, outparam.value is set to the index
     // of the selected username.
-    var ok = this._promptService.select(null,
+    var ok = Services.prompt.select(null,
       dialogTitle, dialogText,
       usernames.length, usernames,
       selectedIndex);
     if (ok) {
       // Now that we know which login to use, modify its password.
       let selectedLogin = logins[selectedIndex.value];
       this.log("Updating password for user " + selectedLogin.username);
       this._updateLogin(selectedLogin, aNewLogin.password);
@@ -325,55 +307,17 @@ LoginManagerPrompter.prototype = {
       propBag.setProperty("password", newPassword);
       // Explicitly set the password change time here (even though it would
       // be changed automatically), to ensure that it's exactly the same
       // value as timeLastUsed.
       propBag.setProperty("timePasswordChanged", now);
     }
     propBag.setProperty("timeLastUsed", now);
     propBag.setProperty("timesUsedIncrement", 1);
-    this._pwmgr.modifyLogin(login, propBag);
-  },
-
-  /*
-   * _getChromeWindow
-   *
-   * Given a content DOM window, returns the chrome window it's in.
-   */
-  _getChromeWindow: function(aWindow) {
-    if (aWindow instanceof Ci.nsIDOMChromeWindow)
-      return aWindow;
-    var chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-      .getInterface(Ci.nsIWebNavigation)
-      .QueryInterface(Ci.nsIDocShell)
-      .chromeEventHandler.ownerGlobal;
-    return chromeWin;
-  },
-
-  /*
-   * _getNativeWindow
-   *
-   * Returns the NativeWindow to this prompter, or null if there isn't
-   * a NativeWindow available (w/ error sent to logcat).
-   */
-  _getNativeWindow: function() {
-    let nativeWindow = null;
-    try {
-      let chromeWin = this._chromeWindow;
-      if (chromeWin.NativeWindow) {
-        nativeWindow = chromeWin.NativeWindow;
-      } else {
-        Cu.reportError("NativeWindow not available on window");
-      }
-
-    } catch (e) {
-      // If any errors happen, just assume no native window helper.
-      Cu.reportError("No NativeWindow available: " + e);
-    }
-    return nativeWindow;
+    Services.logins.modifyLogin(login, propBag);
   },
 
   /*
    * _getLocalizedString
    *
    * Can be called as:
    *   _getLocalizedString("key1");
    *   _getLocalizedString("key2", ["arg1"]);