Bug 1160424 - [Decoder Doctor] Show notification UI when a requested codec is missing but downloadable. r=gijs
authorJared Wein <jwein@mozilla.com>
Sun, 24 Apr 2016 18:04:25 +1000
changeset 332577 0debbed8046d4778751a75625a9a5ccb3ee748e4
parent 332576 bd06fa4221949ade2f42498c48554e498bf2d15a
child 332578 f9ee57defd9ddad86f3545ad512b42d4ea64f640
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs1160424
milestone48.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 1160424 - [Decoder Doctor] Show notification UI when a requested codec is missing but downloadable. r=gijs MozReview-Commit-ID: BHPpLM96cg3
browser/base/content/browser-eme.js
browser/base/content/browser-media.js
browser/base/content/global-scripts.inc
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_decoderDoctor.js
browser/base/jar.mn
browser/modules/ContentObservers.jsm
testing/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
rename from browser/base/content/browser-eme.js
rename to browser/base/content/browser-media.js
--- a/browser/base/content/browser-eme.js
+++ b/browser/base/content/browser-media.js
@@ -176,12 +176,89 @@ var gEMEHandler = {
   },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener])
 };
 
 XPCOMUtils.defineLazyGetter(gEMEHandler, "_brandShortName", function() {
   return document.getElementById("bundle_brand").getString("brandShortName");
 });
 
+let gDecoderDoctorHandler = {
+  shouldShowLearnMoreButton() {
+    return AppConstants.platform == "win";
+  },
+
+  getLabelForNotificationBox(type) {
+    if (type == "adobe-cdm-not-found" &&
+        AppConstants.platform == "win") {
+      if (AppConstants.isPlatformAndVersionAtMost("win", "5.9")) {
+        // We supply our own Learn More button so we don't need to populate the message here.
+        return gNavigatorBundle.getFormattedString("emeNotifications.drmContentDisabled.message", [""]);
+      }
+      return gNavigatorBundle.getString("decoder.noCodecs.message");
+    }
+    if (type == "adobe-cdm-not-activated" &&
+        AppConstants.platform == "win") {
+      if (AppConstants.isPlatformAndVersionAtMost("win", "5.9")) {
+        return gNavigatorBundle.getString("decoder.noCodecsXP.message");
+      }
+      return gNavigatorBundle.getString("decoder.noCodecs.message");
+    }
+    if (type == "platform-decoder-not-found") {
+      if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) {
+        return gNavigatorBundle.getString("decoder.noHWAcceleration.message");
+      }
+      if (AppConstants.platform == "linux") {
+        return gNavigatorBundle.getString("decoder.noCodecsLinux.message");
+      }
+    }
+    return "";
+  },
+
+  receiveMessage({target: browser, data: data}) {
+    let box = gBrowser.getNotificationBox(browser);
+    let notificationId = "decoder-doctor-notification";
+    if (box.getNotificationWithValue(notificationId)) {
+      return;
+    }
+
+    let parsedData;
+    try {
+      parsedData = JSON.parse(data);
+    } catch (ex) {
+      Cu.reportError("Malformed Decoder Doctor message with data: " + data);
+      return;
+    }
+    let {type} = 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");
+        }
+      });
+    }
+
+    box.appendNotification(
+      title,
+      notificationId,
+      "", // This uses the info icon as specified below.
+      box.PRIORITY_INFO_LOW,
+      buttons
+    );
+  },
+}
+
+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);
 }, false);
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -10,21 +10,21 @@
 <script type="application/javascript" src="chrome://browser/content/customizableui/panelUI.js"/>
 <script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
 <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
 
 <script type="application/javascript" src="chrome://browser/content/browser-addons.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-ctrlTab.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-customization.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-devedition.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-eme.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-feeds.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-fullScreen.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-fullZoom.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-gestureSupport.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-media.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-plugins.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-refreshblocker.js"/>
 #ifdef MOZ_SAFE_BROWSING
 <script type="application/javascript" src="chrome://browser/content/browser-safebrowsing.js"/>
 #endif
 <script type="application/javascript" src="chrome://browser/content/browser-sidebar.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-social.js"/>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -278,16 +278,18 @@ skip-if = os == 'win'
 [browser_contextmenu.js]
 tags = fullscreen
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_contextmenu_input.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_ctrlTab.js]
 [browser_datachoices_notification.js]
 skip-if = !datareporting
+[browser_decoderDoctor.js]
+skip-if = os == "mac" # decoder doctor isn't implemented on osx
 [browser_devedition.js]
 [browser_devices_get_user_media.js]
 skip-if = buildapp == 'mulet' || (os == "linux" && debug) # linux: bug 976544
 [browser_devices_get_user_media_about_urls.js]
 skip-if = e10s && debug
 [browser_devices_get_user_media_in_frame.js]
 [browser_discovery.js]
 [browser_double_close_tab.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_decoderDoctor.js
@@ -0,0 +1,94 @@
+"use strict";
+
+function* test_decoder_doctor_notification(type, notificationMessage, options) {
+  yield BrowserTestUtils.withNewTab({ gBrowser }, function*(browser) {
+    let awaitNotificationBar =
+      BrowserTestUtils.waitForNotificationBar(gBrowser, browser, "decoder-doctor-notification");
+
+    yield ContentTask.spawn(browser, type, function*(type) {
+      Services.obs.notifyObservers(content.window,
+                                   "decoder-doctor-notification",
+                                   JSON.stringify({type: type}));
+    });
+
+    let notification;
+    try {
+      notification = yield awaitNotificationBar;
+    } catch (ex) {
+      ok(false, ex);
+      return;
+    }
+    ok(notification, "Got decoder-doctor-notification notification");
+
+    is(notification.getAttribute("label"), notificationMessage,
+      "notification message should match expectation");
+    let button = notification.childNodes[0];
+    if (options && options.noLearnMoreButton) {
+      ok(!button, "There should not be a Learn More button");
+      return;
+    }
+
+    is(button.getAttribute("label"), gNavigatorBundle.getString("decoder.noCodecs.button"),
+      "notification button should be 'Learn more'");
+    is(button.getAttribute("accesskey"), gNavigatorBundle.getString("decoder.noCodecs.accesskey"),
+      "notification button should have accesskey");
+
+    let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
+    let url = baseURL + "fix-video-audio-problems-firefox-windows";
+    let awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, url);
+    button.click();
+    let sumoTab = yield awaitNewTab;
+    yield BrowserTestUtils.removeTab(sumoTab);
+  });
+}
+
+add_task(function* test_adobe_cdm_not_found() {
+  // This is only sent on Windows.
+  if (AppConstants.platform != "win") {
+    return;
+  }
+
+  let message;
+  if (AppConstants.isPlatformAndVersionAtMost("win", "5.9")) {
+    message = gNavigatorBundle.getFormattedString("emeNotifications.drmContentDisabled.message", [""]);
+  } else {
+    message = gNavigatorBundle.getString("decoder.noCodecs.message");
+  }
+
+  yield test_decoder_doctor_notification("adobe-cdm-not-found", message);
+});
+
+add_task(function* test_adobe_cdm_not_activated() {
+  // This is only sent on Windows.
+  if (AppConstants.platform != "win") {
+    return;
+  }
+
+  let message;
+  if (AppConstants.isPlatformAndVersionAtMost("win", "5.9")) {
+    message = gNavigatorBundle.getString("decoder.noCodecsXP.message");
+  } else {
+    message = gNavigatorBundle.getString("decoder.noCodecs.message");
+  }
+
+  yield test_decoder_doctor_notification("adobe-cdm-not-activated", message);
+});
+
+add_task(function* test_platform_decoder_not_found() {
+  // Not sent on Windows XP.
+  if (AppConstants.isPlatformAndVersionAtMost("win", "5.9")) {
+    return;
+  }
+
+  let message;
+  let isLinux = AppConstants.platform == "linux";
+  if (isLinux) {
+    message = gNavigatorBundle.getString("decoder.noCodecsLinux.message");
+  } else {
+    message = gNavigatorBundle.getString("decoder.noHWAcceleration.message");
+  }
+
+  yield test_decoder_doctor_notification("platform-decoder-not-found",
+                                         message,
+                                         {noLearnMoreButton: isLinux});
+});
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -74,22 +74,22 @@ browser.jar:
 *       content/browser/browser.css                   (content/browser.css)
         content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
         content/browser/browser-addons.js             (content/browser-addons.js)
         content/browser/browser-ctrlTab.js            (content/browser-ctrlTab.js)
         content/browser/browser-customization.js      (content/browser-customization.js)
         content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js)
         content/browser/browser-devedition.js         (content/browser-devedition.js)
-        content/browser/browser-eme.js                (content/browser-eme.js)
         content/browser/browser-feeds.js              (content/browser-feeds.js)
         content/browser/browser-fullScreen.js         (content/browser-fullScreen.js)
         content/browser/browser-fullZoom.js           (content/browser-fullZoom.js)
         content/browser/browser-fxaccounts.js         (content/browser-fxaccounts.js)
         content/browser/browser-gestureSupport.js     (content/browser-gestureSupport.js)
+        content/browser/browser-media.js              (content/browser-media.js)
         content/browser/browser-places.js             (content/browser-places.js)
         content/browser/browser-plugins.js            (content/browser-plugins.js)
         content/browser/browser-refreshblocker.js     (content/browser-refreshblocker.js)
 #ifdef MOZ_SAFE_BROWSING
         content/browser/browser-safebrowsing.js       (content/browser-safebrowsing.js)
 #endif
         content/browser/browser-sidebar.js            (content/browser-sidebar.js)
         content/browser/browser-social.js             (content/browser-social.js)
--- a/browser/modules/ContentObservers.jsm
+++ b/browser/modules/ContentObservers.jsm
@@ -22,16 +22,24 @@ Cu.import("resource://gre/modules/Servic
 var gEMEUIObserver = function(subject, topic, data) {
   let win = subject.top;
   let mm = getMessageManagerForWindow(win);
   if (mm) {
     mm.sendAsyncMessage("EMEVideo:ContentMediaKeysRequest", data);
   }
 };
 
+var gDecoderDoctorObserver = function(subject, topic, data) {
+  let win = subject.top;
+  let mm = getMessageManagerForWindow(win);
+  if (mm) {
+    mm.sendAsyncMessage("DecoderDoctor:Notification", data);
+  }
+};
+
 function getMessageManagerForWindow(aContentWindow) {
   let ir = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDocShell)
                          .sameTypeRootTreeItem
                          .QueryInterface(Ci.nsIInterfaceRequestor);
   try {
     // If e10s is disabled, this throws NS_NOINTERFACE for closed tabs.
     return ir.getInterface(Ci.nsIContentFrameMessageManager);
@@ -39,8 +47,9 @@ function getMessageManagerForWindow(aCon
     if (e.result == Cr.NS_NOINTERFACE) {
       return null;
     }
     throw e;
   }
 }
 
 Services.obs.addObserver(gEMEUIObserver, "mediakeys-request", false);
+Services.obs.addObserver(gDecoderDoctorObserver, "decoder-doctor-notification", false);
--- a/testing/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
+++ b/testing/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
@@ -29,21 +29,21 @@ const SCRIPTS = [
   "browser/components/downloads/content/indicator.js",
   "browser/components/customizableui/content/panelUI.js",
   "toolkit/obsolete/content/inlineSpellCheckUI.js",
   "toolkit/components/viewsource/content/viewSourceUtils.js",
   "browser/base/content/browser-addons.js",
   "browser/base/content/browser-ctrlTab.js",
   "browser/base/content/browser-customization.js",
   "browser/base/content/browser-devedition.js",
-  "browser/base/content/browser-eme.js",
   "browser/base/content/browser-feeds.js",
   "browser/base/content/browser-fullScreen.js",
   "browser/base/content/browser-fullZoom.js",
   "browser/base/content/browser-gestureSupport.js",
+  "browser/base/content/browser-media.js",
   "browser/base/content/browser-places.js",
   "browser/base/content/browser-plugins.js",
   "browser/base/content/browser-refreshblocker.js",
   "browser/base/content/browser-safebrowsing.js",
   "browser/base/content/browser-sidebar.js",
   "browser/base/content/browser-social.js",
   "browser/base/content/browser-syncui.js",
   "browser/base/content/browser-tabsintitlebar.js",