Bug 1271483 - p10. Front-end handling of prefs&telemetry - r?gijs draft
authorGerald Squelart <gsquelart@mozilla.com>
Thu, 26 May 2016 00:25:55 +1000
changeset 370939 5b9a301adbb7b6afec93e155f33cd724f7106283
parent 370938 9abe67d9489ae8bd390e44e8da89b14fffefe2b0
child 370940 784a13fa558e4496b71d6860a4866d753a35d668
push id19183
push usergsquelart@mozilla.com
push dateWed, 25 May 2016 16:13:39 +0000
reviewersgijs
bugs1271483
milestone49.0a1
Bug 1271483 - p10. Front-end handling of prefs&telemetry - r?gijs When an issue is reported, save the unplayable formats/key-systesm in a pref, keyed by the detailed issue string id, and report the infobar-shown telemetry. More telemetry when the "Show me how" button is clicked. And final telemetry (and clearing the prefs) when the issue is solved. MozReview-Commit-ID: 4PgaPMVfjsQ
browser/base/content/browser-media.js
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -176,16 +176,22 @@ var gEMEHandler = {
   },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener])
 };
 
 XPCOMUtils.defineLazyGetter(gEMEHandler, "_brandShortName", function() {
   return document.getElementById("bundle_brand").getString("brandShortName");
 });
 
+const TELEMETRY_DDSTAT_SHOWN = 0;
+const TELEMETRY_DDSTAT_SHOWN_FIRST = 1;
+const TELEMETRY_DDSTAT_CLICKED = 2;
+const TELEMETRY_DDSTAT_CLICKED_FIRST = 3;
+const TELEMETRY_DDSTAT_SOLVED = 4;
+
 let gDecoderDoctorHandler = {
   shouldShowLearnMoreButton() {
     return AppConstants.platform == "win";
   },
 
   getLabelForNotificationBox(type) {
     if (type == "adobe-cdm-not-found" &&
         AppConstants.platform == "win") {
@@ -222,42 +228,104 @@ let gDecoderDoctorHandler = {
 
     let parsedData;
     try {
       parsedData = JSON.parse(data);
     } catch (ex) {
       Cu.reportError("Malformed Decoder Doctor message with data: " + data);
       return;
     }
-    let {type} = parsedData;
+    // parsedData (the result of parsing the incoming 'data' json string)
+    // contains analysis information from Decoder Doctor:
+    // - 'type' is the type of issue, it determines which text to show in the
+    //   infobar.
+    // - 'details' is a more-detailed issue identifier, to be used as key for
+    //   the telemetry (counting infobar displays, "show me how" buttons
+    //   clicked, and resolutions) and for the prefs used to store at-issue
+    //   formats.
+    // - 'formats' contains a comma-separated list of formats (or key systems)
+    //   that suffer the issue. These are kept in a pref, which the backend
+    //   uses to later find when an issue is resolved.
+    // - 'isSolved' is true when the notification actually indicates the
+    //   resolution of that issue, to be reported as telemetry.
+    let {type, isSolved, details, formats} = parsedData;
     type = type.toLowerCase();
     let title = gDecoderDoctorHandler.getLabelForNotificationBox(type);
     if (!title) {
       return;
     }
 
-    let buttons = [];
-    if (gDecoderDoctorHandler.shouldShowLearnMoreButton()) {
-      buttons.push({
-        label: gNavigatorBundle.getString("decoder.noCodecs.button"),
-        accessKey: gNavigatorBundle.getString("decoder.noCodecs.accesskey"),
-        callback() {
-          let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
-          openUILinkIn(baseURL + "fix-video-audio-problems-firefox-windows", "tab");
+    let formatsPref = "media.decoder-doctor." + details + ".formats";
+    let buttonClickedPref = "media.decoder-doctor." + details + ".button-clicked";
+    let histogram =
+      Services.telemetry.getKeyedHistogramById("DECODER_DOCTOR_INFOBAR_STATS");
+
+    let formatsInPref = Services.prefs.getPrefType(formatsPref) &&
+                        Services.prefs.getCharPref(formatsPref);
+
+    if (!isSolved) {
+      if (!formats) {
+        Cu.reportError("Malformed Decoder Doctor unsolved message with no formats");
+        return;
+      }
+      if (!formatsInPref) {
+        Services.prefs.setCharPref(formatsPref, formats);
+        histogram.add(details, TELEMETRY_DDSTAT_SHOWN_FIRST);
+      } else {
+        // Split existing formats into an array of strings.
+        let existing = formatsInPref.split(",").map(String.trim);
+        // Keep given formats that were not already recorded.
+        let newbies = formats.split(",")
+                      .map(String.trim)
+                      .filter(x => existing.indexOf(x) < 0);
+        // And rewrite pref with the added new formats (if any).
+        if (newbies.length) {
+          Services.prefs.setCharPref(formatsPref,
+                                     existing.concat(newbies).join(", "));
         }
-      });
-    }
+      }
+      histogram.add(details, TELEMETRY_DDSTAT_SHOWN);
+
+      let buttons = [];
+      if (gDecoderDoctorHandler.shouldShowLearnMoreButton()) {
+        buttons.push({
+          label: gNavigatorBundle.getString("decoder.noCodecs.button"),
+          accessKey: gNavigatorBundle.getString("decoder.noCodecs.accesskey"),
+          callback() {
+            let clickedInPref = Services.prefs.getPrefType(buttonClickedPref) ?
+                                Services.prefs.getIntPref(buttonClickedPref) :
+                                0;
+            if (clickedInPref <= 0) {
+              Services.prefs.setIntPref(buttonClickedPref, 1);
+              histogram.add(details, TELEMETRY_DDSTAT_CLICKED_FIRST);
+            } else {
+              Services.prefs.setIntPref(buttonClickedPref, clickedInPref + 1);
+            }
+            histogram.add(details, TELEMETRY_DDSTAT_CLICKED);
 
-    box.appendNotification(
-      title,
-      notificationId,
-      "", // This uses the info icon as specified below.
-      box.PRIORITY_INFO_LOW,
-      buttons
-    );
+            let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
+            openUILinkIn(baseURL + "fix-video-audio-problems-firefox-windows", "tab");
+          }
+        });
+      }
+
+      box.appendNotification(
+          title,
+          notificationId,
+          "", // This uses the info icon as specified below.
+          box.PRIORITY_INFO_LOW,
+          buttons
+      );
+    } else if (formatsInPref) {
+      // Issue is solved, and prefs haven't been cleared yet, meaning it's the
+      // first time we get this resolution -> Clear prefs and report telemetry.
+      Services.prefs.clearUserPref(formatsPref);
+      Services.prefs.clearUserPref(buttonClickedPref);
+      histogram.add(details, TELEMETRY_DDSTAT_SOLVED);
+    }
   },
 }
 
 window.messageManager.addMessageListener("DecoderDoctor:Notification", gDecoderDoctorHandler);
 window.messageManager.addMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
 window.addEventListener("unload", function() {
   window.messageManager.removeMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
   window.messageManager.removeMessageListener("DecoderDoctor:Notification", gDecoderDoctorHandler);