Bug 1274919 - part5 : add telemetry probe to measure how long the cursor is hovering before opening the tab. draft
authorAlastor Wu <alwu@mozilla.com>
Tue, 18 Jul 2017 16:05:09 +0800
changeset 610371 d346c09b8c4348b1f9bd0dd547e8e342da5588f8
parent 610370 824307c87916d9171ed8483a8075c92d16b5fbea
child 637854 0c3960f778c3aa485fa2c6ce87d8f5971b8d2ae9
push id68884
push useralwu@mozilla.com
push dateTue, 18 Jul 2017 08:56:55 +0000
bugs1274919
milestone56.0a1
Bug 1274919 - part5 : add telemetry probe to measure how long the cursor is hovering before opening the tab. Measure the time how long the cursor is hovering before opening the unselected tab. If the tab didn't be opened, the data won't be recorded. MozReview-Commit-ID: EJNyXXxa7j3
browser/base/content/tabbrowser.xml
toolkit/components/telemetry/Histograms.json
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -5553,16 +5553,17 @@
             // Also support adding event listeners (forward to the tab container)
             addEventListener(a, b, c) { this.self.tabContainer.addEventListener(a, b, c); },
             removeEventListener(a, b, c) { this.self.tabContainer.removeEventListener(a, b, c); }
           });
         ]]>
         </getter>
       </property>
       <field name="_soundPlayingAttrRemovalTimer">0</field>
+      <field name="_hoverTabTimer">0</field>
     </implementation>
 
     <handlers>
       <handler event="DOMWindowClose" phase="capturing">
         <![CDATA[
           if (!event.isTrusted)
             return;
 
@@ -7401,16 +7402,21 @@
           if (val)
             this.setAttribute("visuallyselected", "true");
           else
             this.removeAttribute("visuallyselected");
           this.parentNode.tabbrowser._tabAttrModified(this, ["visuallyselected"]);
 
           this._setPositionAttributes(val);
 
+          // Tab becomes visible, it's not unselected anymore.
+          if (val) {
+            this.finishUnselectedTabHoverTimer();
+          }
+
           return val;
           ]]>
         </setter>
       </property>
 
       <property name="_selected">
         <setter>
           <![CDATA[
@@ -7546,16 +7552,17 @@
               tabContainer._afterHoveredTab = candidate;
               candidate.setAttribute("afterhovered", "true");
             }
           }
 
           tabContainer._hoveredTab = this;
           if (!this.selected) {
             this.linkedBrowser.unselectedTabHover(true);
+            this.startUnselectedTabHoverTimer();
           }
         ]]></body>
       </method>
 
       <method name="_mouseleave">
         <body><![CDATA[
           let tabContainer = this.parentNode;
           if (tabContainer._beforeHoveredTab) {
@@ -7565,16 +7572,62 @@
           if (tabContainer._afterHoveredTab) {
             tabContainer._afterHoveredTab.removeAttribute("afterhovered");
             tabContainer._afterHoveredTab = null;
           }
 
           tabContainer._hoveredTab = null;
           if (!this.selected) {
             this.linkedBrowser.unselectedTabHover(false);
+            this.cancelUnselectedTabHoverTimer();
+          }
+        ]]></body>
+      </method>
+
+      <method name="startUnselectedTabHoverTimer">
+        <body><![CDATA[
+          // Only record data when we need to.
+          if (!this.linkedBrowser.shouldHandleUnselectedTabHover) {
+            return;
+          }
+
+          if (!TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
+            TelemetryStopwatch.start("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
+          }
+
+          if (this._hoverTabTimer != 0) {
+            clearTimeout(this._hoverTabTimer);
+            this._hoverTabTimer = 0;
+          }
+        ]]></body>
+      </method>
+
+      <method name="cancelUnselectedTabHoverTimer">
+        <body><![CDATA[
+          // Since we're listening "mouseout" event, instead of "mouseleave".
+          // Every time the cursor is moving from the tab to its child node (icon),
+          // it would dispatch "mouseout"(for tab) first and then dispatch
+          // "mouseover" (for icon, eg: close button, speaker icon) soon.
+          // It causes we would cancel present TelemetryStopwatch immediately
+          // when cursor is moving on the icon, and then start a new one.
+          // In order to avoid this situation, we could delay cancellation and
+          // remove it if we get "mouseover" within very short period.
+          this._hoverTabTimer = setTimeout(() => {
+            if (TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
+              TelemetryStopwatch.cancel("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
+            }
+          }, 100);
+        ]]></body>
+      </method>
+
+      <method name="finishUnselectedTabHoverTimer">
+        <body><![CDATA[
+          // Stop timer when the tab is opened.
+          if (TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
+            TelemetryStopwatch.finish("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
           }
         ]]></body>
       </method>
 
       <method name="startMediaBlockTimer">
         <body><![CDATA[
           TelemetryStopwatch.start("TAB_MEDIA_BLOCKING_TIME_MS", this);
         ]]></body>
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13626,10 +13626,21 @@
     "bug_numbers": [1368524],
     "expires_in_version": "60",
     "kind": "exponential",
     "low": 3,
     "high": 512,
     "n_buckets": 20,
     "keyed": true,
     "description": "Measures the number of milliseconds we spend synchronously notifying observers, keyed by topic. Note: only NotifyObservers calls which take over 500 microseconds are included in this probe."
+  },
+  "HOVER_UNTIL_UNSELECTED_TAB_OPENED": {
+    "record_in_processes": ["main"],
+    "alert_emails": ["alwu@mozilla.com"],
+    "expires_in_version": "60",
+    "kind": "exponential",
+    "high": 10000,
+    "n_buckets": 100,
+    "bug_numbers": [1274919],
+    "description": "Measure the time how long the cursor is hovering before opening the unselcted tab. Only record the data if someone requests for sending unselected tab hover msg.",
+    "releaseChannelCollection": "opt-out"
   }
 }