Bug 1461656 - Ask permission when site wants to autoplay media. r=flod,johannh
authorDale Harvey <dale@arandomurl.com>
Fri, 18 May 2018 12:54:33 +0100
changeset 479520 f527be41b97db03959f4c8116e5f76f58d49a1a5
parent 479519 94e0de0c19d1dfaeb32d6a982df38168ace23825
child 479529 c40cc0a89bc70511751d17ed0cdd569a74abac88
child 479530 b19a1ccabd8959ccd11c1eb50cdaae5487cacc24
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflod, johannh
bugs1461656
milestone62.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 1461656 - Ask permission when site wants to autoplay media. r=flod,johannh MozReview-Commit-ID: Fc2IUZK90eu
browser/base/content/browser-siteIdentity.js
browser/base/content/browser.xul
browser/components/nsBrowserGlue.js
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
browser/modules/PermissionUI.jsm
browser/modules/SitePermissions.jsm
browser/modules/test/browser/browser_PermissionUI_prompts.js
browser/themes/shared/jar.inc.mn
browser/themes/shared/notification-icons.inc.css
browser/themes/shared/notification-icons/autoplay-media-blocked.svg
browser/themes/shared/notification-icons/autoplay-media.svg
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -1051,17 +1051,19 @@ var gIdentityHandler = {
       if (aPermission.state == SitePermissions.getDefault(aPermission.id)) {
         menulist.value = "0";
       } else {
         menulist.value = aPermission.state;
       }
 
       // Avoiding listening to the "select" event on purpose. See Bug 1404262.
       menulist.addEventListener("command", () => {
-        SitePermissions.set(gBrowser.currentURI, "popup", menulist.selectedItem.value);
+        SitePermissions.set(gBrowser.currentURI,
+                            aPermission.id,
+                            menulist.selectedItem.value);
       });
 
       container.appendChild(img);
       container.appendChild(nameLabel);
       container.appendChild(menulist);
       block.appendChild(container);
 
       return block;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -819,32 +819,36 @@
                   <image data-permission-id="microphone" class="blocked-permission-icon microphone-icon" role="button"
                          tooltiptext="&urlbar.microphoneBlocked.tooltip;"/>
                   <image data-permission-id="screen" class="blocked-permission-icon screen-icon" role="button"
                          tooltiptext="&urlbar.screenBlocked.tooltip;"/>
                   <image data-permission-id="persistent-storage" class="blocked-permission-icon persistent-storage-icon" role="button"
                          tooltiptext="&urlbar.persistentStorageBlocked.tooltip;"/>
                   <image data-permission-id="popup" class="blocked-permission-icon popup-icon" role="button"
                          tooltiptext="&urlbar.popupBlocked.tooltip;"/>
+                  <image data-permission-id="autoplay-media" class="blocked-permission-icon autoplay-media-icon" role="button"
+                         tooltiptext="&urlbar.autoplayMediaBlocked.tooltip;"/>
                   <image data-permission-id="canvas" class="blocked-permission-icon canvas-icon" role="button"
                          tooltiptext="&urlbar.canvasBlocked.tooltip;"/>
                   <image data-permission-id="plugin:flash" class="blocked-permission-icon plugin-icon" role="button"
                          tooltiptext="&urlbar.flashPluginBlocked.tooltip;"/>
                   <image data-permission-id="midi" class="blocked-permission-icon midi-icon" role="button"
                          tooltiptext="&urlbar.midiBlocked.tooltip;"/>
                 </box>
                 <box id="notification-popup-box"
                      hidden="true"
                      onmouseover="document.getElementById('identity-box').classList.add('no-hover');"
                      onmouseout="document.getElementById('identity-box').classList.remove('no-hover');"
                      align="center">
                   <image id="default-notification-icon" class="notification-anchor-icon" role="button"
                          tooltiptext="&urlbar.defaultNotificationAnchor.tooltip;"/>
                   <image id="geo-notification-icon" class="notification-anchor-icon geo-icon" role="button"
                          tooltiptext="&urlbar.geolocationNotificationAnchor.tooltip;"/>
+                  <image id="autoplay-media-notification-icon" class="notification-anchor-icon autoplay-media-icon" role="button"
+                         tooltiptext="&urlbar.autoplayNotificationAnchor.tooltip;"/>
                   <image id="addons-notification-icon" class="notification-anchor-icon install-icon" role="button"
                          tooltiptext="&urlbar.addonsNotificationAnchor.tooltip;"/>
                   <image id="canvas-notification-icon" class="notification-anchor-icon" role="button"
                          tooltiptext="&urlbar.canvasNotificationAnchor.tooltip;"/>
                   <image id="indexedDB-notification-icon" class="notification-anchor-icon indexedDB-icon" role="button"
                          tooltiptext="&urlbar.indexedDBNotificationAnchor.tooltip;"/>
                   <image id="password-notification-icon" class="notification-anchor-icon login-icon" role="button"
                          tooltiptext="&urlbar.passwordNotificationAnchor.tooltip;"/>
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2838,16 +2838,19 @@ const ContentPermissionIntegration = {
         return new PermissionUI.DesktopNotificationPermissionPrompt(request);
       }
       case "persistent-storage": {
         return new PermissionUI.PersistentStoragePermissionPrompt(request);
       }
       case "midi": {
         return new PermissionUI.MIDIPermissionPrompt(request);
       }
+      case "autoplay-media": {
+        return new PermissionUI.AutoplayPermissionPrompt(request);
+      }
     }
     return undefined;
   },
 };
 
 function ContentPermissionPrompt() {}
 
 ContentPermissionPrompt.prototype = {
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -208,16 +208,17 @@ These should match what Safari and other
 <!ENTITY goEndCap.tooltip             "Go to the address in the Location Bar">
 <!ENTITY printButton.label            "Print">
 <!ENTITY printButton.tooltip          "Print this page">
 
 <!ENTITY urlbar.viewSiteInfo.label                      "View site information">
 
 <!ENTITY urlbar.defaultNotificationAnchor.tooltip         "Open message panel">
 <!ENTITY urlbar.geolocationNotificationAnchor.tooltip     "Open location request panel">
+<!ENTITY urlbar.autoplayNotificationAnchor.tooltip        "Open autoplay panel">
 <!ENTITY urlbar.addonsNotificationAnchor.tooltip          "Open add-on installation message panel">
 <!ENTITY urlbar.canvasNotificationAnchor.tooltip          "Manage canvas extraction permission">
 <!ENTITY urlbar.indexedDBNotificationAnchor.tooltip       "Open offline storage message panel">
 <!ENTITY urlbar.passwordNotificationAnchor.tooltip        "Open save password message panel">
 <!ENTITY urlbar.pluginsNotificationAnchor.tooltip         "Manage plug-in use">
 <!ENTITY urlbar.webNotificationAnchor.tooltip             "Change whether you can receive notifications from the site">
 <!ENTITY urlbar.persistentStorageNotificationAnchor.tooltip     "Store data in Persistent Storage">
 <!ENTITY urlbar.remoteControlNotificationAnchor.tooltip   "Browser is under remote control">
@@ -235,16 +236,17 @@ These should match what Safari and other
 
 <!ENTITY urlbar.cameraBlocked.tooltip            "You have blocked your camera for this website.">
 <!ENTITY urlbar.microphoneBlocked.tooltip        "You have blocked your microphone for this website.">
 <!ENTITY urlbar.screenBlocked.tooltip            "You have blocked this website from sharing your screen.">
 <!ENTITY urlbar.geolocationBlocked.tooltip       "You have blocked location information for this website.">
 <!ENTITY urlbar.webNotificationsBlocked.tooltip  "You have blocked notifications for this website.">
 <!ENTITY urlbar.persistentStorageBlocked.tooltip "You have blocked persistent storage for this website.">
 <!ENTITY urlbar.popupBlocked.tooltip             "You have blocked pop-ups for this website.">
+<!ENTITY urlbar.autoplayMediaBlocked.tooltip     "You have blocked autoplay media with sound for this website.">
 <!ENTITY urlbar.canvasBlocked.tooltip            "You have blocked canvas data extraction for this website.">
 <!ENTITY urlbar.flashPluginBlocked.tooltip       "You have blocked this website from using the Adobe Flash plugin.">
 <!ENTITY urlbar.midiBlocked.tooltip              "You have blocked MIDI access for this website.">
 
 <!ENTITY urlbar.openHistoryPopup.tooltip                "Show history">
 
 <!ENTITY searchItem.title             "Search">
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -946,12 +946,20 @@ midi.DontAllow.accesskey = N
 midi.remember=Remember this decision
 midi.shareWithFile.message = Will you allow this local file to access your MIDI Devices?
 # LOCALIZATION NOTE (midi.shareWithSite.message): %S is the name of the site URL (https://...) requesting MIDI access
 midi.shareWithSite.message = Will you allow %S to access your MIDI Devices?
 midi.shareSysexWithFile.message = Will you allow this local file to access your MIDI devices and send/receive SysEx messages?
 # LOCALIZATION NOTE (midi.shareSysexWithSite.message): %S is the name of the site URL (https://...) requesting MIDI access
 midi.shareSysexWithSite.message = Will you allow %S to access your MIDI devices and send/receive SysEx messages?
 
+autoplay.Allow.label = Allow Autoplay
+autoplay.Allow.accesskey = A
+autoplay.DontAllow.label = Don’t Allow
+autoplay.DontAllow.accesskey = n
+autoplay.remember = Remember this decision
+# LOCALIZATION NOTE (autoplay.message): %S is the name of the site URL (https://...) trying to autoplay media
+autoplay.message = Will you allow %S to autoplay media with sound?
+autoplay.messageWithFile = Will you allow this file to autoplay media with sound?
 # LOCALIZATION NOTE (panel.back):
 # This is used by screen readers to label the "back" button in various browser
 # popup panels, including the sliding subviews of the main menu.
 panel.back = Back
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -742,8 +742,69 @@ MIDIPermissionPrompt.prototype = {
     }];
   },
 
   onBeforeShow() {
   },
 };
 
 PermissionUI.MIDIPermissionPrompt = MIDIPermissionPrompt;
+
+function AutoplayPermissionPrompt(request) {
+  this.request = request;
+}
+
+AutoplayPermissionPrompt.prototype = {
+  __proto__: PermissionPromptForRequestPrototype,
+
+  get permissionKey() {
+    return "autoplay-media";
+  },
+
+  get popupOptions() {
+    let checkbox = {
+      show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal) &&
+        !this.principal.URI.schemeIs("file")
+    };
+    if (checkbox.show) {
+      checkbox.checked = true;
+      checkbox.label = gBrowserBundle.GetStringFromName("autoplay.remember");
+    }
+    return {
+      checkbox,
+      displayURI: false,
+      name: this.principal.URI.hostPort,
+    };
+  },
+
+  get notificationID() {
+    return "autoplay-media";
+  },
+
+  get anchorID() {
+    return "autoplay-media-icon";
+  },
+
+  get message() {
+    if (this.principal.URI.schemeIs("file")) {
+      return gBrowserBundle.GetStringFromName("autoplay.messageWithFile");
+    }
+    return gBrowserBundle.formatStringFromName("autoplay.message", ["<>"], 1);
+  },
+
+  get promptActions() {
+    return [{
+        label: gBrowserBundle.GetStringFromName("autoplay.Allow.label"),
+        accessKey: gBrowserBundle.GetStringFromName("autoplay.Allow.accesskey"),
+        action: Ci.nsIPermissionManager.ALLOW_ACTION,
+      },
+      {
+        label: gBrowserBundle.GetStringFromName("autoplay.DontAllow.label"),
+        accessKey: gBrowserBundle.GetStringFromName("autoplay.DontAllow.accesskey"),
+        action: Ci.nsIPermissionManager.DENY_ACTION,
+    }];
+  },
+
+  onBeforeShow() {
+  },
+};
+
+PermissionUI.AutoplayPermissionPrompt = AutoplayPermissionPrompt;
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -606,18 +606,19 @@ var gPermissionObject = {
    */
 
   "autoplay-media": {
     exactHostMatch: true,
     getDefault() {
       if (Services.prefs.getBoolPref("media.autoplay.enabled")) {
         return SitePermissions.ALLOW;
       }
-      return SitePermissions.BLOCK;
-    }
+      return SitePermissions.UNKNOWN;
+    },
+    labelID: "autoplay-media"
   },
 
   "image": {
     states: [ SitePermissions.ALLOW, SitePermissions.BLOCK ],
   },
 
   "cookie": {
     states: [ SitePermissions.ALLOW, SitePermissions.ALLOW_COOKIES_FOR_SESSION, SitePermissions.BLOCK ],
--- a/browser/modules/test/browser/browser_PermissionUI_prompts.js
+++ b/browser/modules/test/browser/browser_PermissionUI_prompts.js
@@ -25,16 +25,23 @@ add_task(async function test_persistent_
   await testPrompt(PermissionUI.PersistentStoragePermissionPrompt);
 });
 
 // Tests that MidiPrompt works as expected
 add_task(async function test_midi_permission_prompt() {
   await testPrompt(PermissionUI.MIDIPermissionPrompt);
 });
 
+// Tests that AutoplayPermissionPrompt works as expected
+add_task(async function test_autoplay_permission_prompt() {
+  Services.prefs.setBoolPref("media.autoplay.enabled", false);
+  await testPrompt(PermissionUI.AutoplayPermissionPrompt);
+  Services.prefs.clearUserPref("media.autoplay.enabled");
+});
+
 async function testPrompt(Prompt) {
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: "http://example.com",
   }, async function(browser) {
     let mockRequest = makeMockPermissionRequest(browser);
     let principal = mockRequest.principal;
     let TestPrompt = new Prompt(mockRequest);
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -50,16 +50,18 @@
   skin/classic/browser/connection-mixed-active-loaded.svg      (../shared/identity-block/connection-mixed-active-loaded.svg)
   skin/classic/browser/identity-icon.svg                       (../shared/identity-block/identity-icon.svg)
   skin/classic/browser/identity-icon-notice.svg                (../shared/identity-block/identity-icon-notice.svg)
   skin/classic/browser/info.svg                                (../shared/info.svg)
   skin/classic/browser/searchReset.css                         (../shared/searchReset.css)
 
   skin/classic/browser/illustrations/error-session-restore.svg (../shared/illustrations/error-session-restore.svg)
 
+  skin/classic/browser/notification-icons/autoplay-media.svg                (../shared/notification-icons/autoplay-media.svg)
+  skin/classic/browser/notification-icons/autoplay-media-blocked.svg        (../shared/notification-icons/autoplay-media-blocked.svg)
   skin/classic/browser/notification-icons/camera-blocked.svg                (../shared/notification-icons/camera-blocked.svg)
   skin/classic/browser/notification-icons/camera.svg                        (../shared/notification-icons/camera.svg)
   skin/classic/browser/notification-icons/canvas-blocked.svg                (../shared/notification-icons/canvas-blocked.svg)
   skin/classic/browser/notification-icons/canvas.svg                        (../shared/notification-icons/canvas.svg)
   skin/classic/browser/notification-icons/default-info.svg                  (../shared/notification-icons/default-info.svg)
   skin/classic/browser/notification-icons/desktop-notification-blocked.svg  (../shared/notification-icons/desktop-notification-blocked.svg)
   skin/classic/browser/notification-icons/desktop-notification.svg          (../shared/notification-icons/desktop-notification.svg)
   skin/classic/browser/notification-icons/focus-tab-by-prompt.svg           (../shared/notification-icons/focus-tab-by-prompt.svg)
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -52,16 +52,25 @@
 .geo-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/geo.svg);
 }
 
 .geo-icon.blocked-permission-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/geo-blocked.svg);
 }
 
+.popup-notification-icon[popupid="autoplay-media"],
+.autoplay-media-icon {
+  list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media.svg);
+}
+
+.autoplay-media-icon.blocked-permission-icon {
+  list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media-blocked.svg);
+}
+
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/notification-icons/geo-detailed.svg);
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .indexedDB-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/indexedDB.svg);
 }
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/notification-icons/autoplay-media-blocked.svg
@@ -0,0 +1,10 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
+    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <path d="M9.94970307,6.4383516 C8.40256713,7.13481327 7.27358134,8.59523862 7.04329506,10.3390783 L5.85914977,11.0232511 C5.68193745,11.1255647 5.46360318,11.1255661 5.28638956,11.0232548 C5.10917593,10.9209434 5.0000052,10.7318625 5,10.5272353 L5,4.57046357 C5.00082111,4.36624583 5.11031415,4.17791321 5.28737873,4.0761601 C5.46444331,3.97440698 5.68229154,3.97462749 5.85914977,4.07673884 L9.94970307,6.4383516 Z" fill="#000000" fill-rule="nonzero"></path>
+        <path d="M13.5616811,5.14867232 C12.6193302,2.72101341 10.2606472,1 7.5,1 C3.91014913,1 1,3.91014913 1,7.5 C1,10.8017358 3.46176769,13.528495 6.64994254,13.9449169" stroke="#000000" stroke-width="1.5" stroke-linecap="round"></path>
+        <path d="M12,7 C9.790861,7 8,8.790861 8,11 C8,13.209139 9.790861,15 12,15 C14.209139,15 16,13.209139 16,11 C16,8.790861 14.209139,7 12,7 Z M12,8 C12.6220042,8.00091132 13.2280791,8.19675778 13.733,8.56 L9.56,12.733 C8.90610356,11.8203472 8.81838019,10.6183679 9.33283825,9.62044577 C9.8472963,8.62252365 10.8772778,7.99675388 12,8 Z M12,14 C11.3779958,13.9990887 10.7719209,13.8032422 10.267,13.44 L14.44,9.267 C15.0938964,10.1796528 15.1816198,11.3816321 14.6671618,12.3795542 C14.1527037,13.3774764 13.1227222,14.0032461 12,14 Z" fill="#000000" fill-rule="nonzero"></path>
+    </g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/notification-icons/autoplay-media.svg
@@ -0,0 +1,7 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
+  <path d="M8 2a6 6 0 1 0 6 6 6.007 6.007 0 0 0-6-6zm0 11a5 5 0 1 1 5-5 5.006 5.006 0 0 1-5 5z"></path>
+  <path d="M6.75 4.969A.5.5 0 0 0 6 5.4v5.2a.5.5 0 0 0 .75.433l4.5-2.6a.5.5 0 0 0 0-.866z"></path>
+</svg>