WIP dialog telemetry. draft
authorChenxia Liu <liuche@mozilla.com>
Fri, 06 Feb 2015 11:39:03 -0800
changeset 241811 c450893ca2444a6caad138be7e08d3e30663fba9
parent 241810 c121fcf2c4f11c661544425414bea7415c3feaeb
child 505272 e6b8c53c06c8ad938243e0ea7987e157ef2d9aca
push id619
push usercliu@mozilla.com
push dateMon, 09 Feb 2015 21:57:21 +0000
milestone38.0a1
WIP dialog telemetry.
mobile/android/components/LoginManagerPrompter.js
toolkit/components/passwordmgr/nsLoginManagerPrompter.js
toolkit/components/telemetry/Histograms.json
--- a/mobile/android/components/LoginManagerPrompter.js
+++ b/mobile/android/components/LoginManagerPrompter.js
@@ -5,16 +5,25 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
+/* Constants for password prompt telemetry.
+ * Mirrored in nsLoginManagerPrompter.js */
+const PROMPT_RES_SAVE = 1;
+const PROMPT_RES_UPDATE = 2;
+const PROMPT_RES_NOTNOW = 3;
+const PROMPT_RES_NEVER = 4;
+const PROMPT_RES_DISMISS = 5;
+const PROMPT_RES_REMOVE = 6;
+
 /* ==================== LoginManagerPrompter ==================== */
 /*
  * LoginManagerPrompter
  *
  * Implements interfaces for prompting the user to enter/save/change auth info.
  *
  * nsILoginManagerPrompter: Used by Login Manager for saving/changing logins
  * found in HTML forms.
@@ -170,27 +179,31 @@ LoginManagerPrompter.prototype = {
         } else {
             notificationText  = this._getLocalizedString("savePasswordNoUser", [displayHost]);
         }
 
         // 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 pwmgr = this._pwmgr;
+        let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_SELECTION_STATE");
+
 
         var buttons = [
             {
                 label: this._getLocalizedString("saveButton"),
                 callback: function() {
                     pwmgr.addLogin(aLogin);
+                    promptHistogram.add(PROMPT_RES_SAVE);
                 }
             },
             {
                 label: this._getLocalizedString("dontSaveButton"),
                 callback: function() {
+                    promptHistogram.add(PROMPT_RES_NOTNOW);
                     // Don't set a permanent exception
                 }
             }
         ];
 
         this._showLoginNotification("password-save", notificationText, buttons);
     },
 
@@ -220,27 +233,30 @@ LoginManagerPrompter.prototype = {
         } 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_SELECTION_STATE");
 
         var buttons = [
             {
                 label: this._getLocalizedString("updateButton"),
                 callback:  function() {
                     self._updateLogin(aOldLogin, aNewPassword);
+                    promptHistogram.add(PROMPT_RES_UPDATE);
                 }
             },
             {
                 label: this._getLocalizedString("dontUpdateButton"),
                 callback:  function() {
+                    promptHistogram.add(PROMPT_RES_NOTNOW);
                     // do nothing
                 }
             }
         ];
 
         this._showLoginNotification("password-change", notificationText, buttons);
     },
 
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -8,16 +8,25 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource://gre/modules/SharedPromptUtils.jsm");
 
+/* Constants for password prompt telemetry.
+ * Mirrored in mobile/android/components/LoginManagerPrompter.js */
+const PROMPT_RES_SAVE = 1;
+const PROMPT_RES_UPDATE = 2;
+const PROMPT_RES_NOTNOW = 3;
+const PROMPT_RES_NEVER = 4;
+const PROMPT_RES_DISMISS = 5;
+const PROMPT_RES_REMOVE = 6;
+
 /*
  * LoginManagerPromptFactory
  *
  * Implements nsIPromptFactory
  *
  * Invoked by [toolkit/components/prompts/src/nsPrompter.js]
  */
 function LoginManagerPromptFactory() {
@@ -465,16 +474,17 @@ LoginManagerPrompter.prototype = {
       var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
                      createInstance(Ci.nsILoginInfo);
       newLogin.init(hostname, null, realm, username,
                     aPassword.value, "", "");
 
       this.log("New login seen for " + realm);
 
       this._pwmgr.addLogin(newLogin);
+      this.log("2: New login added");
     }
 
     return ok;
   },
 
   /* ---------- nsIAuthPrompt helpers ---------- */
 
 
@@ -614,20 +624,24 @@ LoginManagerPrompter.prototype = {
         this.log("New login seen for " + username +
                  " @ " + hostname + " (" + httpRealm + ")");
 
         var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
                        createInstance(Ci.nsILoginInfo);
         newLogin.init(hostname, null, httpRealm,
                       username, password, "", "");
         var notifyObj = this._getPopupNote() || notifyBox;
-        if (notifyObj)
+        if (notifyObj) {
           this._showSaveLoginNotification(notifyObj, newLogin);
-        else
+          this.log("3a: showing notification");
+        }
+        else {
           this._pwmgr.addLogin(newLogin);
+          this.log("3b: New login added");
+        }
 
       } else if (password != selectedLogin.password) {
 
         this.log("Updating password for " + username +
                  " @ " + hostname + " (" + httpRealm + ")");
         var notifyObj = this._getPopupNote() || notifyBox;
         if (notifyObj)
           this._showChangeLoginNotification(notifyObj,
@@ -767,30 +781,37 @@ LoginManagerPrompter.prototype = {
     newBar.timeout = Date.now() + 20000; // 20 seconds
 
     if (oldBar) {
       this.log("(...and removing old " + aName + " notification bar)");
       aNotifyBox.removeNotification(oldBar);
     }
   },
 
+  _notificationCallback : function (aEvent) {
+    switch(aEvent) {
+      case "dismissed":
+        this.log("*** dismiss");
+        Services.telemetry.getHistogramById("PWMGR_PROMPT_SELECTION_STATE").add(PROMPT_RES_DISMISS);
+        break;
+    }
+  },
 
   /*
    * _showSaveLoginNotification
    *
    * Displays a notification bar or a popup notification, 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.
    *
    * @param aNotifyObj
    *        A notification box or a popup notification.
    */
   _showSaveLoginNotification : function (aNotifyObj, aLogin) {
-
-    // Ugh. We can't use the strings from the popup window, because they
+        // Ugh. We can't use the strings from the popup window, because they
     // have the access key marked in the string (eg "Mo&zilla"), along
     // with some weird rules for handling access keys that do not occur
     // in the string, for L10N. See commonDialog.js's setLabelForNode().
     var neverButtonText =
           this._getLocalizedString("notifyBarNeverRememberButtonText");
     var neverButtonAccessKey =
           this._getLocalizedString("notifyBarNeverRememberButtonAccessKey");
     var rememberButtonText =
@@ -811,78 +832,93 @@ LoginManagerPrompter.prototype = {
                                   [displayHost]);
     }
 
     // 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 pwmgr = this._pwmgr;
 
+    let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_SELECTION_STATE");
+    let self = this;
+
     // Notification is a PopupNotification
     if (aNotifyObj == this._getPopupNote()) {
       // "Remember" button
       var mainAction = {
         label:     rememberButtonText,
         accessKey: rememberButtonAccessKey,
         callback: function(aNotifyObj, aButton) {
+          self.log("*** save1");
+          promptHistogram.add(PROMPT_RES_SAVE);
           pwmgr.addLogin(aLogin);
           browser.focus();
         }
       };
 
       var secondaryActions = [
         // "Never for this site" button
         {
           label:     neverButtonText,
           accessKey: neverButtonAccessKey,
           callback: function(aNotifyObj, aButton) {
+            self.log("*** never1");
+            promptHistogram.add(PROMPT_RES_NEVER);
             pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
             browser.focus();
           }
         }
       ];
 
       var { browser } = this._getNotifyWindow();
 
       aNotifyObj.show(browser, "password-save", notificationText,
                       "password-notification-icon", mainAction,
                       secondaryActions, { timeout: Date.now() + 10000,
-                                          persistWhileVisible: true });
+                                          persistWhileVisible: true,
+                                          eventCallback: this._notificationCallback.bind(this) });
     } else {
       var notNowButtonText =
             this._getLocalizedString("notifyBarNotNowButtonText");
       var notNowButtonAccessKey =
             this._getLocalizedString("notifyBarNotNowButtonAccessKey");
       var buttons = [
         // "Remember" button
         {
           label:     rememberButtonText,
           accessKey: rememberButtonAccessKey,
           popup:     null,
           callback: function(aNotifyObj, aButton) {
+            self.log("*** save2");
+            promptHistogram.add(PROMPT_RES_SAVE);
             pwmgr.addLogin(aLogin);
           }
         },
 
         // "Never for this site" button
         {
           label:     neverButtonText,
           accessKey: neverButtonAccessKey,
           popup:     null,
           callback: function(aNotifyObj, aButton) {
+            self.log("*** never2");
+            promptHistogram.add(PROMPT_RES_NEVER);
             pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
           }
         },
 
         // "Not now" button
         {
           label:     notNowButtonText,
           accessKey: notNowButtonAccessKey,
           popup:     null,
-          callback:  function() { /* NOP */ }
+          callback:  function() {
+            self.log("*** notnow2");
+            promptHistogram.add(PROMPT_RES_NOTNOW);
+          }
         }
       ];
 
       this._showLoginNotification(aNotifyObj, "password-save",
                                   notificationText, buttons);
     }
   },
 
@@ -918,16 +954,17 @@ LoginManagerPrompter.prototype = {
   /*
    * _showSaveLoginDialog
    *
    * Called when we detect a new login in a form submission,
    * asks the user what to do.
    *
    */
   _showSaveLoginDialog : function (aLogin) {
+    this.log("====== 4: showSaveLoginDialog ======");
     const buttonFlags = Ci.nsIPrompt.BUTTON_POS_1_DEFAULT +
         (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
         (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1) +
         (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2);
 
     var displayHost = this._getShortDisplayHost(aLogin.hostname);
 
     var dialogText;
@@ -1018,57 +1055,64 @@ LoginManagerPrompter.prototype = {
     var changeButtonAccessKey =
           this._getLocalizedString("notifyBarUpdateButtonAccessKey");
 
     // 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_SELECTION_STATE");
     // Notification is a PopupNotification
     if (aNotifyObj == this._getPopupNote()) {
       // "Yes" button
       var mainAction = {
         label:     changeButtonText,
         accessKey: changeButtonAccessKey,
         popup:     null,
         callback:  function(aNotifyObj, aButton) {
           self._updateLogin(aOldLogin, aNewPassword);
+          self.log("*** update3");
+          promptHistogram.add(PROMPT_RES_UPDATE);
         }
       };
 
       var { browser } = this._getNotifyWindow();
 
       aNotifyObj.show(browser, "password-change", notificationText,
                       "password-notification-icon", mainAction,
                       null, { timeout: Date.now() + 10000,
-                              persistWhileVisible: true });
+                              persistWhileVisible: true,
+                              eventCallback: this._notificationCallback.bind(this) });
     } else {
       var dontChangeButtonText =
             this._getLocalizedString("notifyBarDontChangeButtonText");
       var dontChangeButtonAccessKey =
             this._getLocalizedString("notifyBarDontChangeButtonAccessKey");
       var buttons = [
         // "Yes" button
         {
           label:     changeButtonText,
           accessKey: changeButtonAccessKey,
           popup:     null,
           callback:  function(aNotifyObj, aButton) {
+            self.log("*** update4");
+            promptHistogram.add(PROMPT_RES_UPDATE);
             self._updateLogin(aOldLogin, aNewPassword);
           }
         },
 
         // "No" button
         {
           label:     dontChangeButtonText,
           accessKey: dontChangeButtonAccessKey,
           popup:     null,
           callback:  function(aNotifyObj, aButton) {
-            // do nothing
+            self.log("*** notnow4");
+            promptHistogram.add(PROMPT_RES_NOTNOW);
           }
         }
       ];
 
       this._showLoginNotification(aNotifyObj, "password-change",
                                   notificationText, buttons);
     }
   },
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -7332,16 +7332,22 @@
   },
   "PWMGR_LOGIN_LAST_USED_DAYS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 750,
     "n_buckets" : 40,
     "description": "Time in days each saved login was last used"
   },
+  "PWMGR_PROMPT_SELECTION_STATE": {
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": 10,
+    "description": "Selection made by user through prompt for creating or modifying a login" 
+  },
   "PWMGR_SAVING_ENABLED": {
     "expires_in_version": "never",
     "kind": "boolean",
     "description": "Number of users who have password saving on globally"
   },
   "PWMGR_USERNAME_PRESENT": {
     "expires_in_version": "never",
     "kind": "boolean",