Bug 1102937 - Add UITelemetry for the improved search bar UI. r=florian, r=felipe
authorBlake Winton <bwinton@latte.ca>
Tue, 06 Jan 2015 13:09:43 -0500
changeset 248234 368f0748e882be78773e35586cea61614bccf72e
parent 248233 854a6dbbd5e4cce6798d20dbaa0a3e6835b6b36e
child 248235 78d6f61ef9807c36b5f8f09dbdaca62f47553d08
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian, felipe
bugs1102937
milestone37.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 1102937 - Add UITelemetry for the improved search bar UI. r=florian, r=felipe
browser/base/content/browser.js
browser/base/content/urlbarBindings.xml
browser/components/search/content/search.xml
browser/modules/BrowserUITelemetry.jsm
toolkit/content/widgets/autocomplete.xml
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3563,16 +3563,21 @@ const BrowserSearch = {
       return;
     }
 
     let countId = this._getSearchEngineId(engine) + "." + source;
 
     let count = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
     count.add(countId);
   },
+
+  recordOneoffSearchInTelemetry: function (engine, source, type, where) {
+    let id = this._getSearchEngineId(engine) + "." + source;
+    BrowserUITelemetry.countOneoffSearchEvent(id, type, where);
+  }
 };
 
 const SearchHighlight = {
   eventsReady: false,
   // The pref that controls how many times to show the highlight.
   countPref: "browser.search.highlightCount",
   // The current highlight to show.
   currentPos: 0,
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -918,24 +918,29 @@
         <body><![CDATA[
           // Ignore all right-clicks
           if (aEvent.button == 2)
             return;
 
           var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
 
           // Check for unmodified left-click, and use default behavior
+          var searchBar = BrowserSearch.searchBar;
+          searchBar.telemetrySearchDetails = {
+            index: controller.selection.currentIndex,
+            kind: "mouse"
+          };
+
           if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
               !aEvent.altKey && !aEvent.metaKey) {
             controller.handleEnter(true);
             return;
           }
 
           // Check for middle-click or modified clicks on the search bar
-          var searchBar = BrowserSearch.searchBar;
           if (searchBar && searchBar.textbox == this.mInput) {
             // Handle search bar popup clicks
             var search = controller.getValueAt(this.selectedIndex);
 
             // close the autocomplete popup and revert the entered search term
             this.closePopup();
             controller.handleEscape();
 
@@ -991,17 +996,17 @@
         <xul:label anonid="searchbar-oneoffheader-after" flex="10000" value="&searchWith.label;"/>
       </xul:hbox>
       <xul:description anonid="search-panel-one-offs"
                        class="search-panel-one-offs"
                        xbl:inherits="hidden=showonlysettings"/>
       <xul:vbox anonid="add-engines"/>
       <xul:button anonid="search-settings"
                   xbl:inherits="showonlysettings"
-                  oncommand="openPreferences('paneSearch')"
+                  oncommand="BrowserUITelemetry.countSearchSettingsEvent('searchbar');openPreferences('paneSearch')"
                   class="search-setting-button search-panel-header"
                   label="&changeSearchSettings.button;"/>
     </content>
     <implementation>
       <method name="updateHeader">
         <body><![CDATA[
           let currentEngine = Services.search.currentEngine;
           let uri = currentEngine.iconURI;
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -496,43 +496,72 @@
 #ifdef XP_MACOSX
                                                    aEvent.metaKey))
 #else
                                                    aEvent.ctrlKey))
 #endif
               where = "tab-background";
           }
 
+          let selection = this.telemetrySearchDetails;
           this.doSearch(textValue, where, aEngine);
+
+          if (!selection || (selection.index == -1)) {
+            let target = aEvent.originalTarget;
+            let source = "unknown";
+            let type = "unknown";
+            if (aEvent instanceof KeyboardEvent) {
+              type = "key";
+              if (this._textbox.getSelectedOneOff()) {
+                source = "oneoff";
+              }
+            } else if (aEvent instanceof MouseEvent) {
+              type = "mouse";
+              if (target.classList.contains("searchbar-engine-one-off-item")) {
+                source = "oneoff";
+              } else if (target.classList.contains("search-panel-header") ||
+                         target.parentNode.classList.contains("search-panel-header")) {
+                source = "header";
+              }
+            }
+
+            BrowserSearch.recordOneoffSearchInTelemetry(aEngine, source, type, where);
+          }
+
           if (where == "tab-background")
             this.focus();
         ]]></body>
       </method>
 
       <method name="doSearch">
         <parameter name="aData"/>
         <parameter name="aWhere"/>
         <parameter name="aEngine"/>
         <body><![CDATA[
           var textBox = this._textbox;
-        
+
           // Save the current value in the form history
           if (aData && !PrivateBrowsingUtils.isWindowPrivate(window)) {
             this.FormHistory.update(
               { op : "bump",
                 fieldname : textBox.getAttribute("autocompletesearchparam"),
                 value : aData },
               { handleError : function(aError) {
                   Components.utils.reportError("Saving search to form history failed: " + aError.message);
               }});
           }
 
           let engine = aEngine || this.currentEngine;
           var submission = engine.getSubmission(aData, null, "searchbar");
-          BrowserSearch.recordSearchInHealthReport(engine, "searchbar");
+          let telemetrySearchDetails = this.telemetrySearchDetails;
+          this.telemetrySearchDetails = null;
+          if (telemetrySearchDetails && telemetrySearchDetails.index == -1) {
+            telemetrySearchDetails = null;
+          }
+          BrowserSearch.recordSearchInHealthReport(engine, "searchbar", telemetrySearchDetails);
           // null parameter below specifies HTML response for search
           let params = {
             postData: submission.postData,
             inBackground: aWhere == "tab-background"
           };
           openUILinkIn(submission.uri.spec,
                        aWhere == "tab-background" ? "tab" : aWhere,
                        params);
@@ -937,16 +966,21 @@
         <parameter name="aEvent"/>
         <body><![CDATA[
           var evt = aEvent || this.mEnterEvent;
 
           let engine;
           let oneOff = this.getSelectedOneOff();
           if (oneOff)
             engine = oneOff.engine;
+          if (this.mEnterEvent && this._selectionDetails &&
+              this._selectionDetails.currentIndex != -1) {
+            BrowserSearch.searchBar.telemetrySearchDetails = this._selectionDetails;
+            this._selectionDetails = null;
+          }
           document.getBindingParent(this).handleSearchCommand(evt, engine);
 
           this.mEnterEvent = null;
         ]]></body>
       </method>
 
       <method name="getSelectedOneOff">
         <body><![CDATA[
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -280,19 +280,21 @@ this.BrowserUITelemetry = {
     // our measurements because at that point all browser windows have
     // probably been closed, since the vast majority of saved-session
     // pings are gathered during shutdown.
     let win = RecentWindow.getMostRecentBrowserWindow({
       private: false,
       allowPopups: false,
     });
 
-    // If there are no such windows, we're out of luck. :(
-    this._firstWindowMeasurements = win ? this._getWindowMeasurements(win)
-                                        : {};
+    Services.search.init(rv => {
+      // If there are no such windows, we're out of luck. :(
+      this._firstWindowMeasurements = win ? this._getWindowMeasurements(win, rv)
+                                          : {};
+    });
   },
 
   _registerWindow: function(aWindow) {
     aWindow.addEventListener("unload", this);
     let document = aWindow.document;
 
     for (let areaID of CustomizableUI.areas) {
       let areaNode = document.getElementById(areaID);
@@ -459,17 +461,17 @@ this.BrowserUITelemetry = {
     // If not, we need to check if one of the ancestors of the clicked
     // item is in our list of built-in items to check.
     let candidate = getIDBasedOnFirstIDedAncestor(item);
     if (ALL_BUILTIN_ITEMS.indexOf(candidate) != -1) {
       this._countMouseUpEvent("click-builtin-item", candidate, aEvent.button);
     }
   },
 
-  _getWindowMeasurements: function(aWindow) {
+  _getWindowMeasurements: function(aWindow, searchResult) {
     let document = aWindow.document;
     let result = {};
 
     // Determine if the window is in the maximized, normal or
     // fullscreen state.
     result.sizemode = document.documentElement.getAttribute("sizemode");
 
     // Determine if the Bookmarks bar is currently visible
@@ -548,16 +550,20 @@ this.BrowserUITelemetry = {
         let visibleTabsNum = someWin.gBrowser.visibleTabs.length;
         visibleTabs.push(visibleTabsNum);
         hiddenTabs.push(someWin.gBrowser.tabs.length - visibleTabsNum);
       }
     }
     result.visibleTabs = visibleTabs;
     result.hiddenTabs = hiddenTabs;
 
+    if (Components.isSuccessCode(searchResult)) {
+      result.currentSearchEngine = Services.search.currentEngine;
+    }
+
     return result;
   },
 
   getToolbarMeasures: function() {
     let result = this._firstWindowMeasurements || {};
     result.countableEvents = this._countableEvents;
     result.durations = this._durations;
     return result;
@@ -572,16 +578,24 @@ this.BrowserUITelemetry = {
     if ((/^[a-zA-Z]+:[^\/\\]/).test(query)) {
       this._countEvent(["search", "urlbar-keyword"]);
     }
     if (selection) {
       this._countEvent(["search", "selection", source, selection.index, selection.kind]);
     }
   },
 
+  countOneoffSearchEvent: function(id, type, where) {
+    this._countEvent(["search-oneoff", id, type, where]);
+  },
+
+  countSearchSettingsEvent: function(source) {
+    this._countEvent(["click-builtin-item", source, "search-settings"]);
+  },
+
   _logAwesomeBarSearchResult: function (url) {
     let spec = Services.search.parseSubmissionURL(url);
     if (spec.engine) {
       let matchedEngine = "default";
       if (spec.engine.name !== Services.search.currentEngine.name) {
         matchedEngine = "other";
       }
       this.countSearchEvent("autocomplete-" + matchedEngine);
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -417,16 +417,17 @@
             return (new Function("eventType", "param", handlerString)).bind(this, aEventType);
           }
           return null;
         ]]></body>
       </method>
 
       <!-- ::::::::::::: key handling ::::::::::::: -->
 
+      <field name="_selectionDetails">null</field>
       <method name="onKeyPress">
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (aEvent.target.localName != "textbox")
             return true; // Let child buttons of autocomplete take input
 
           //XXXpch this is so bogus...
           if (aEvent.defaultPrevented)
@@ -480,16 +481,22 @@
               break;
             case KeyEvent.DOM_VK_RETURN:
 #ifdef XP_MACOSX
               // Prevent the default action, since it will beep on Mac
               if (aEvent.metaKey)
                 aEvent.preventDefault();
 #endif
               this.mEnterEvent = aEvent;
+              if (this.mController.selection) {
+                this._selectionDetails = {
+                  index: this.mController.selection.currentIndex,
+                  kind: "key"
+                };
+              }
               cancel = this.mController.handleEnter(false);
               break;
             case KeyEvent.DOM_VK_DELETE:
 #ifdef XP_MACOSX
             case KeyEvent.DOM_VK_BACK_SPACE:
               if (aEvent.shiftKey)
 #endif
               cancel = this.mController.handleDelete();