 |
1 # -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6 let gEMEHandler = {
7 ensureEMEEnabled: function(browser, keySystem) {
8 Services.prefs.setBoolPref("media.eme.enabled", true);
9 if (keySystem) {
10 if (keySystem.startsWith("com.adobe") &&
11 Services.prefs.getPrefType("media.gmp-eme-adobe.enabled") &&
12 !Services.prefs.getBoolPref("media.gmp-eme-adobe.enabled")) {
13 Services.prefs.setBoolPref("media.gmp-eme-adobe.enabled", true);
14 } else if (keySystem == "org.w3.clearkey" &&
15 Services.prefs.getPrefType("media.eme.clearkey.enabled") &&
16 !Services.prefs.getBoolPref("media.eme.clearkey.enabled")) {
17 Services.prefs.setBoolPref("media.eme.clearkey.enabled", true);
18 }
19 }
20 browser.reload();
21 },
22 getLearnMoreLink: function(msgId) {
23 let text = gNavigatorBundle.getString("emeNotifications." + msgId + ".learnMoreLabel");
24 let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
25 return "<label class='text-link' href='" + baseURL + "drm-content'>" +
26 text + "</label>";
27 },
28 onDontAskAgain: function(menuPopupItem) {
29 let button = menuPopupItem.parentNode.anchorNode;
30 let bar = button.parentNode;
31 Services.prefs.setBoolPref("browser.eme.ui." + bar.value + ".disabled", true);
32 bar.close();
33 },
34 onNotNow: function(menuPopupItem) {
35 let button = menuPopupItem.parentNode.anchorNode;
36 button.parentNode.close();
37 },
38 receiveMessage: function({target: browser, data: data}) {
39 let parsedData;
40 try {
41 parsedData = JSON.parse(data);
42 } catch (ex) {
43 Cu.reportError("Malformed EME video message with data: " + data);
44 return;
45 }
46 let {status: status, keySystem: keySystem} = parsedData;
47 // Don't need to show if disabled
48 if (!Services.prefs.getBoolPref("browser.eme.ui.enabled")) {
49 return;
50 }
51
52 let notificationId;
53 let buttonCallback;
54 let params = [];
55 switch (status) {
56 case "available":
57 case "cdm-created":
58 this.showPopupNotificationForSuccess(browser, keySystem);
59 // ... and bail!
60 return;
61
62 case "api-disabled":
63 case "cdm-disabled":
64 notificationId = "drmContentDisabled";
65 buttonCallback = gEMEHandler.ensureEMEEnabled.bind(gEMEHandler, browser, keySystem)
66 params = [this.getLearnMoreLink(notificationId)];
67 break;
68
69 case "cdm-not-supported":
70 notificationId = "drmContentCDMNotSupported";
71 params = [this._brandShortName, this.getLearnMoreLink(notificationId)];
72 break;
73
74 case "cdm-insufficient-version":
75 notificationId = "drmContentCDMInsufficientVersion";
76 params = [this._brandShortName];
77 break;
78
79 case "cdm-not-installed":
80 notificationId = "drmContentCDMInstalling";
81 params = [this._brandShortName];
82 break;
83
84 case "error":
85 // Fall through and do the same for unknown messages:
86 default:
87 let typeOfIssue = status == "error" ? "error" : "message ('" + status + "')";
88 Cu.reportError("Unknown " + typeOfIssue + " dealing with EME key request: " + data);
89 return;
90 }
91
92 this.showNotificationBar(browser, notificationId, keySystem, params, buttonCallback);
93 },
94 showNotificationBar: function(browser, notificationId, keySystem, labelParams, callback) {
95 let box = gBrowser.getNotificationBox(browser);
96 if (box.getNotificationWithValue(notificationId)) {
97 return;
98 }
99
100 // If the user turned these off, bail out:
101 try {
102 if (Services.prefs.getBoolPref("browser.eme.ui." + notificationId + ".disabled")) {
103 return;
104 }
105 } catch (ex) { /* Don't care if the pref doesn't exist */ }
106
107 let msgPrefix = "emeNotifications." + notificationId + ".";
108 let msgId = msgPrefix + "message";
109
110 // Specialcase Adobe's CDM on unsupported platforms to be more informative:
111 if (notificationId == "drmContentCDMNotSupported" &&
112 keySystem.startsWith("com.adobe")) {
113 let os = Services.appinfo.OS.toLowerCase();
114 if (os.startsWith("win") && Services.appinfo.XPCOMABI.startsWith("x86_64")) {
115 msgId = msgPrefix + "64bit.message";
116 } else if (os.startsWith("linux") || os.startsWith("darwin")) {
117 msgId = msgPrefix + "unsupportedOS.message";
118 labelParams.splice(1, 0, os.startsWith("linux") ? "Linux" : "Mac OS X");
119 }
120 }
121
122 let message = labelParams.length ?
123 gNavigatorBundle.getFormattedString(msgId, labelParams) :
124 gNavigatorBundle.getString(msgId);
125
126 let buttons = [];
127 if (callback) {
128 let btnLabelId = msgPrefix + "button.label";
129 let btnAccessKeyId = msgPrefix + "button.accesskey";
130 buttons.push({
131 label: gNavigatorBundle.getString(btnLabelId),
132 accessKey: gNavigatorBundle.getString(btnAccessKeyId),
133 callback: callback
134 });
135
136 let optionsId = "emeNotifications.optionsButton";
137 buttons.push({
138 label: gNavigatorBundle.getString(optionsId + ".label"),
139 accessKey: gNavigatorBundle.getString(optionsId + ".accesskey"),
140 popup: "emeNotificationsPopup"
141 });
142 }
143
144 let iconURL = "chrome://browser/skin/drm-icon.svg#chains-black";
145
146 // Do a little dance to get rich content into the notification:
147 let fragment = document.createDocumentFragment();
148 let descriptionContainer = document.createElement("description");
149 descriptionContainer.innerHTML = message;
150 while (descriptionContainer.childNodes.length) {
151 fragment.appendChild(descriptionContainer.childNodes[0]);
152 }
153
154 box.appendNotification(fragment, notificationId, iconURL, box.PRIORITY_WARNING_MEDIUM,
155 buttons);
156 },
157 showPopupNotificationForSuccess: function(browser, keySystem) {
158 // We're playing EME content! Remove any "we can't play because..." messages.
159 var box = gBrowser.getNotificationBox(browser);
160 ["drmContentDisabled",
161 "drmContentCDMNotSupported",
162 "drmContentCDMInsufficientVersion",
163 "drmContentCDMInstalling"
164 ].forEach(function (value) {
165 var notification = box.getNotificationWithValue(value);
166 if (notification)
167 box.removeNotification(notification);
168 });
169
170 // Don't bother creating it if it's already there:
171 if (PopupNotifications.getNotification("drmContentPlaying", browser)) {
172 return;
173 }
174
175 let msgPrefix = "emeNotifications.drmContentPlaying.";
176 let msgId = msgPrefix + "message2";
177 let btnLabelId = msgPrefix + "button.label";
178 let btnAccessKeyId = msgPrefix + "button.accesskey";
179
180 let message = gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
181 let anchorId = "eme-notification-icon";
182 let firstPlayPref = "browser.eme.ui.firstContentShown";
183 if (!Services.prefs.getPrefType(firstPlayPref) ||
184 !Services.prefs.getBoolPref(firstPlayPref)) {
185 document.getElementById(anchorId).setAttribute("firstplay", "true");
186 Services.prefs.setBoolPref(firstPlayPref, true);
187 } else {
188 document.getElementById(anchorId).removeAttribute("firstplay");
189 }
190
191
192 let mainAction = {
193 label: gNavigatorBundle.getString(btnLabelId),
194 accessKey: gNavigatorBundle.getString(btnAccessKeyId),
195 callback: function() { openPreferences("paneContent"); },
196 dismiss: true
197 };
198 let options = {
199 dismissed: true,
200 eventCallback: aTopic => aTopic == "swapping",
201 };
202 PopupNotifications.show(browser, "drmContentPlaying", message, anchorId, mainAction, null, options);
203 },
204 QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener])
205 };
206
207 XPCOMUtils.defineLazyGetter(gEMEHandler, "_brandShortName", function() {
208 return document.getElementById("bundle_brand").getString("brandShortName");
209 });
210
211 window.messageManager.addMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
212 window.addEventListener("unload", function() {
213 window.messageManager.removeMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
214 }, false);
215