зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1543812 - Add ability to block all autoplay. r=johannh,alwu,flod,fluent-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D30135 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
aef340f83f
Коммит
87fa55e513
|
@ -1518,7 +1518,7 @@ pref("media.gmp-gmpopenh264.enabled", true);
|
|||
// Switch block autoplay logic to v2, and enable UI.
|
||||
pref("media.autoplay.enabled.user-gestures-needed", true);
|
||||
// Set Firefox to block autoplay, asking for permission by default.
|
||||
pref("media.autoplay.default", 1); // 0=Allowed, 1=Blocked
|
||||
pref("media.autoplay.default", 1); // 0=Allowed, 1=Blocked, 5=All Blocked
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Block WebAudio from playing automatically.
|
||||
|
|
|
@ -643,7 +643,8 @@ var gIdentityHandler = {
|
|||
// show permission icons
|
||||
let permissions = SitePermissions.getAllForBrowser(gBrowser.selectedBrowser);
|
||||
for (let permission of permissions) {
|
||||
if (permission.state == SitePermissions.BLOCK) {
|
||||
if (permission.state == SitePermissions.BLOCK ||
|
||||
permission.state == SitePermissions.AUTOPLAY_BLOCKED_ALL) {
|
||||
let icon = permissionAnchors[permission.id];
|
||||
if (icon) {
|
||||
icon.setAttribute("showing", "true");
|
||||
|
@ -1141,7 +1142,8 @@ var gIdentityHandler = {
|
|||
} else {
|
||||
menuitem.setAttribute("value", state);
|
||||
}
|
||||
menuitem.setAttribute("label", SitePermissions.getMultichoiceStateLabel(state));
|
||||
|
||||
menuitem.setAttribute("label", SitePermissions.getMultichoiceStateLabel(aPermission.id, state));
|
||||
menupopup.appendChild(menuitem);
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ function createRow(aPartId) {
|
|||
for (let state of SitePermissions.getAvailableStates(aPartId)) {
|
||||
let radio = document.createXULElement("radio");
|
||||
radio.setAttribute("id", aPartId + "#" + state);
|
||||
radio.setAttribute("label", SitePermissions.getMultichoiceStateLabel(state));
|
||||
radio.setAttribute("label", SitePermissions.getMultichoiceStateLabel(aPartId, state));
|
||||
radio.setAttribute("command", commandId);
|
||||
radiogroup.appendChild(radio);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ support-files =
|
|||
support-files =
|
||||
browser_autoplay_blocked.html
|
||||
browser_autoplay_blocked_slow.sjs
|
||||
browser_autoplay_muted.html
|
||||
../general/audio.ogg
|
||||
skip-if = verify && os == 'linux' && debug # Bug 1483648
|
||||
[browser_temporary_permissions_expiry.js]
|
||||
|
|
|
@ -6,6 +6,8 @@ const AUTOPLAY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/c
|
|||
|
||||
const SLOW_AUTOPLAY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "browser_autoplay_blocked_slow.sjs";
|
||||
|
||||
const MUTED_AUTOPLAY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "browser_autoplay_muted.html";
|
||||
|
||||
const AUTOPLAY_PREF = "media.autoplay.default";
|
||||
const AUTOPLAY_PERM = "autoplay-media";
|
||||
|
||||
|
@ -80,15 +82,15 @@ add_task(async function testMainViewVisible() {
|
|||
is(labels[0].textContent, labelText, "Correct value");
|
||||
|
||||
let menulist = document.getElementById("identity-popup-popup-menulist");
|
||||
Assert.equal(menulist.label, "Block");
|
||||
Assert.equal(menulist.label, "Block Audio");
|
||||
|
||||
await EventUtils.synthesizeMouseAtCenter(menulist, { type: "mousedown" });
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return menulist.getElementsByTagName("menuitem")[0].label === "Allow";
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return menulist.getElementsByTagName("menuitem")[0].label === "Allow Audio and Video";
|
||||
});
|
||||
|
||||
let menuitem = menulist.getElementsByTagName("menuitem")[0];
|
||||
Assert.equal(menuitem.getAttribute("label"), "Allow");
|
||||
Assert.equal(menuitem.getAttribute("label"), "Allow Audio and Video ");
|
||||
|
||||
menuitem.click();
|
||||
menulist.menupopup.hidePopup();
|
||||
|
@ -155,6 +157,7 @@ add_task(async function testChangingBlockingSettingDuringNavigation() {
|
|||
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
|
||||
|
||||
await BrowserTestUtils.withNewTab("about:home", async function(browser) {
|
||||
await blockedIconHidden();
|
||||
await BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE);
|
||||
await blockedIconShown();
|
||||
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.ALLOWED);
|
||||
|
@ -193,3 +196,29 @@ add_task(async function testSlowLoadingPage() {
|
|||
|
||||
Services.perms.removeAll();
|
||||
});
|
||||
|
||||
add_task(async function testBlockedAll() {
|
||||
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED_ALL);
|
||||
|
||||
await BrowserTestUtils.withNewTab("about:home", async function(browser) {
|
||||
await blockedIconHidden();
|
||||
await BrowserTestUtils.loadURI(browser, MUTED_AUTOPLAY_PAGE);
|
||||
await blockedIconShown();
|
||||
|
||||
await openIdentityPopup();
|
||||
|
||||
let menulist = document.getElementById("identity-popup-popup-menulist");
|
||||
await EventUtils.synthesizeMouseAtCenter(menulist, { type: "mousedown" });
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return menulist.getElementsByTagName("menuitem")[1].label === "Block Audio";
|
||||
});
|
||||
|
||||
let menuitem = menulist.getElementsByTagName("menuitem")[0];
|
||||
menuitem.click();
|
||||
menulist.menupopup.hidePopup();
|
||||
await closeIdentityPopup();
|
||||
gBrowser.reload();
|
||||
await blockedIconHidden();
|
||||
});
|
||||
Services.perms.removeAll();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- 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/. -->
|
||||
<html dir="ltr" xml:lang="en-US" lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
<body>
|
||||
<audio autoplay="autoplay" muted>
|
||||
<source src="audio.ogg" />
|
||||
</audio>
|
||||
</body>
|
||||
</html>
|
|
@ -288,16 +288,12 @@ var gPrivacyPane = {
|
|||
/* Initialize Content Blocking */
|
||||
this.initContentBlocking();
|
||||
|
||||
this.blockAutoplayReadPrefs();
|
||||
this.trackingProtectionReadPrefs();
|
||||
this.networkCookieBehaviorReadPrefs();
|
||||
this._initTrackingProtectionExtensionControl();
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled("pwmgr", true);
|
||||
|
||||
Preferences.get("media.autoplay.default").on("change",
|
||||
gPrivacyPane.blockAutoplayReadPrefs.bind(gPrivacyPane));
|
||||
|
||||
Preferences.get("privacy.trackingprotection.enabled").on("change",
|
||||
gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane));
|
||||
Preferences.get("privacy.trackingprotection.pbmode.enabled").on("change",
|
||||
|
@ -361,6 +357,8 @@ var gPrivacyPane = {
|
|||
this._initMasterPasswordUI();
|
||||
this._initSafeBrowsing();
|
||||
|
||||
setEventListener("autoplaySettingsButton", "command",
|
||||
gPrivacyPane.showAutoplayMediaExceptions);
|
||||
setEventListener("notificationSettingsButton", "command",
|
||||
gPrivacyPane.showNotificationExceptions);
|
||||
setEventListener("locationSettingsButton", "command",
|
||||
|
@ -371,10 +369,6 @@ var gPrivacyPane = {
|
|||
gPrivacyPane.showMicrophoneExceptions);
|
||||
setEventListener("popupPolicyButton", "command",
|
||||
gPrivacyPane.showPopupExceptions);
|
||||
setEventListener("autoplayMediaCheckbox", "command",
|
||||
gPrivacyPane.toggleAutoplayMedia);
|
||||
setEventListener("autoplayMediaPolicyButton", "command",
|
||||
gPrivacyPane.showAutoplayMediaExceptions);
|
||||
setEventListener("notificationsDoNotDisturb", "command",
|
||||
gPrivacyPane.toggleDoNotDisturbNotifications);
|
||||
|
||||
|
@ -1291,31 +1285,10 @@ var gPrivacyPane = {
|
|||
|
||||
// MEDIA
|
||||
|
||||
blockAutoplayReadPrefs() {
|
||||
let blocked =
|
||||
Preferences.get("media.autoplay.default").value == Ci.nsIAutoplay.BLOCKED;
|
||||
document.getElementById("autoplayMediaCheckbox").checked = blocked;
|
||||
},
|
||||
|
||||
/**
|
||||
* The checkbox enabled sets the pref to BLOCKED
|
||||
*/
|
||||
toggleAutoplayMedia(event) {
|
||||
let blocked = event.target.checked ? Ci.nsIAutoplay.BLOCKED : Ci.nsIAutoplay.ALLOWED;
|
||||
Services.prefs.setIntPref("media.autoplay.default", blocked);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the autoplay exceptions dialog where specific site autoplay preferences
|
||||
* can be set.
|
||||
*/
|
||||
showAutoplayMediaExceptions() {
|
||||
var params = {
|
||||
blockVisible: true, sessionVisible: false, allowVisible: true,
|
||||
prefilledHost: "", permissionType: "autoplay-media",
|
||||
};
|
||||
var params = { permissionType: "autoplay-media" };
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
gSubDialog.open("chrome://browser/content/preferences/sitePermissions.xul",
|
||||
"resizable=yes", params);
|
||||
},
|
||||
|
||||
|
|
|
@ -708,33 +708,39 @@
|
|||
" />
|
||||
</hbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<vbox id="notificationsDoNotDisturbBox" hidden="true">
|
||||
<checkbox id="notificationsDoNotDisturb" class="indent"/>
|
||||
<vbox id="notificationsDoNotDisturbBox" hidden="true">
|
||||
<checkbox id="notificationsDoNotDisturb" class="indent"/>
|
||||
</vbox>
|
||||
|
||||
<hbox id="autoplaySettingsRow" align="center" role="group" aria-labelledby="autoplayPermissionsLabel">
|
||||
<description flex="1">
|
||||
<image class="autoplay-icon permission-icon" />
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<label id="autoplayPermissionsLabel"
|
||||
data-l10n-id="permissions-autoplay"/>
|
||||
</description>
|
||||
<hbox pack="end">
|
||||
<button id="autoplaySettingsButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-autoplay-settings"
|
||||
search-l10n-ids="
|
||||
permissions-remove.label,
|
||||
permissions-remove-all.label,
|
||||
permissions-button-cancel.label,
|
||||
permissions-button-ok.label,
|
||||
permissions-site-autoplay-window.title,
|
||||
permissions-site-autoplay-desc,
|
||||
permissions-site-autoplay-disable-label,
|
||||
permissions-site-autoplay-disable-desc,
|
||||
" />
|
||||
</hbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<separator flex="1"/>
|
||||
|
||||
<hbox align="start" id="autoplayMediaCheckboxWrapper">
|
||||
<checkbox id="autoplayMediaCheckbox"
|
||||
data-l10n-id="permissions-block-autoplay-media2"
|
||||
flex="1" />
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="autoplayMediaPolicyButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-block-autoplay-media-exceptions"
|
||||
search-l10n-ids="permissions-address,
|
||||
permissions-button-cancel.label,
|
||||
permissions-button-ok.label,
|
||||
permissions-exceptions-autoplay-media-window2.title,
|
||||
permissions-exceptions-autoplay-media-desc2
|
||||
" />
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
||||
<hbox data-subcategory="permissions-block-popups">
|
||||
<checkbox id="popupPolicy" preference="dom.disable_open_during_load"
|
||||
data-l10n-id="permissions-block-popups"
|
||||
|
|
|
@ -26,10 +26,6 @@ const permissionExceptionsL10n = {
|
|||
window: "permissions-exceptions-addons-window",
|
||||
description: "permissions-exceptions-addons-desc",
|
||||
},
|
||||
"autoplay-media": {
|
||||
window: "permissions-exceptions-autoplay-media-window2",
|
||||
description: "permissions-exceptions-autoplay-media-desc2",
|
||||
},
|
||||
};
|
||||
|
||||
function Permission(principal, type, capability) {
|
||||
|
|
|
@ -33,6 +33,26 @@ const sitePermissionsL10n = {
|
|||
disableLabel: "permissions-site-microphone-disable-label",
|
||||
disableDescription: "permissions-site-microphone-disable-desc",
|
||||
},
|
||||
"autoplay-media": {
|
||||
window: "permissions-site-autoplay-window",
|
||||
description: "permissions-site-autoplay-desc",
|
||||
},
|
||||
};
|
||||
|
||||
const sitePermissionsConfig = {
|
||||
"autoplay-media": {
|
||||
_getCapabilityString(capability) {
|
||||
switch (capability) {
|
||||
case SitePermissions.ALLOW:
|
||||
return "permissions-capabilities-autoplay-allow";
|
||||
case SitePermissions.BLOCK:
|
||||
return "permissions-capabilities-autoplay-block";
|
||||
case SitePermissions.AUTOPLAY_BLOCKED_ALL:
|
||||
return "permissions-capabilities-autoplay-blockall";
|
||||
}
|
||||
throw new Error(`Unknown capability: ${capability}`);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function Permission(principal, type, capability, l10nId) {
|
||||
|
@ -43,10 +63,16 @@ function Permission(principal, type, capability, l10nId) {
|
|||
this.l10nId = l10nId;
|
||||
}
|
||||
|
||||
const PERMISSION_STATES = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.PROMPT];
|
||||
const PERMISSION_STATES = [
|
||||
SitePermissions.ALLOW, SitePermissions.BLOCK,
|
||||
SitePermissions.PROMPT, SitePermissions.AUTOPLAY_BLOCKED_ALL,
|
||||
];
|
||||
|
||||
const NOTIFICATIONS_PERMISSION_OVERRIDE_KEY = "webNotificationsDisabled";
|
||||
const NOTIFICATIONS_PERMISSION_PREF = "permissions.default.desktop-notification";
|
||||
|
||||
const AUTOPLAY_PREF = "media.autoplay.default";
|
||||
|
||||
var gSitePermissionsManager = {
|
||||
_type: "",
|
||||
_isObserving: false,
|
||||
|
@ -80,13 +106,18 @@ var gSitePermissionsManager = {
|
|||
this._checkbox = document.getElementById("permissionsDisableCheckbox");
|
||||
this._disableExtensionButton = document.getElementById("disableNotificationsPermissionExtension");
|
||||
this._permissionsDisableDescription = document.getElementById("permissionsDisableDescription");
|
||||
this._setAutoplayPref = document.getElementById("setAutoplayPref");
|
||||
|
||||
let permissionsText = document.getElementById("permissionsText");
|
||||
|
||||
let l10n = sitePermissionsL10n[this._type];
|
||||
document.l10n.setAttributes(permissionsText, l10n.description);
|
||||
document.l10n.setAttributes(this._checkbox, l10n.disableLabel);
|
||||
document.l10n.setAttributes(this._permissionsDisableDescription, l10n.disableDescription);
|
||||
if (l10n.disableLabel) {
|
||||
document.l10n.setAttributes(this._checkbox, l10n.disableLabel);
|
||||
}
|
||||
if (l10n.disableDescription) {
|
||||
document.l10n.setAttributes(this._permissionsDisableDescription, l10n.disableDescription);
|
||||
}
|
||||
document.l10n.setAttributes(document.documentElement, l10n.window);
|
||||
|
||||
await document.l10n.translateElements([
|
||||
|
@ -104,6 +135,11 @@ var gSitePermissionsManager = {
|
|||
this._loadPermissions();
|
||||
this.buildPermissionsList();
|
||||
|
||||
if (params.permissionType == "autoplay-media") {
|
||||
this.buildAutoplayMenulist();
|
||||
this._setAutoplayPref.hidden = false;
|
||||
}
|
||||
|
||||
this._searchBox.focus();
|
||||
},
|
||||
|
||||
|
@ -112,6 +148,9 @@ var gSitePermissionsManager = {
|
|||
Services.obs.removeObserver(this, "perm-changed");
|
||||
this._isObserving = false;
|
||||
}
|
||||
if (this._setAutoplayPref) {
|
||||
this._setAutoplayPref.hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
|
@ -130,7 +169,7 @@ var gSitePermissionsManager = {
|
|||
} else if (data == "changed") {
|
||||
let p = this._permissions.get(permission.principal.origin);
|
||||
p.capability = permission.capability;
|
||||
p.l10nId = this._getCapabilityString(permission.capability);
|
||||
p.l10nId = this._getCapabilityString(permission.type, permission.capability);
|
||||
this._handleCapabilityChange(p);
|
||||
this.buildPermissionsList();
|
||||
} else if (data == "deleted") {
|
||||
|
@ -207,29 +246,29 @@ var gSitePermissionsManager = {
|
|||
}
|
||||
},
|
||||
|
||||
_getCapabilityString(capability) {
|
||||
let stringKey = null;
|
||||
_getCapabilityString(type, capability) {
|
||||
if (type in sitePermissionsConfig &&
|
||||
sitePermissionsConfig[type]._getCapabilityString) {
|
||||
return sitePermissionsConfig[type]._getCapabilityString(capability);
|
||||
}
|
||||
|
||||
switch (capability) {
|
||||
case Services.perms.ALLOW_ACTION:
|
||||
stringKey = "permissions-capabilities-allow";
|
||||
break;
|
||||
return "permissions-capabilities-allow";
|
||||
case Services.perms.DENY_ACTION:
|
||||
stringKey = "permissions-capabilities-block";
|
||||
break;
|
||||
return "permissions-capabilities-block";
|
||||
case Services.perms.PROMPT_ACTION:
|
||||
stringKey = "permissions-capabilities-prompt";
|
||||
break;
|
||||
return "permissions-capabilities-prompt";
|
||||
default:
|
||||
throw new Error(`Unknown capability: ${capability}`);
|
||||
}
|
||||
return stringKey;
|
||||
},
|
||||
|
||||
_addPermissionToList(perm) {
|
||||
// Ignore unrelated permission types and permissions with unknown states.
|
||||
if (perm.type !== this._type || !PERMISSION_STATES.includes(perm.capability))
|
||||
return;
|
||||
let l10nId = this._getCapabilityString(perm.capability);
|
||||
let l10nId = this._getCapabilityString(perm.type, perm.capability);
|
||||
let p = new Permission(perm.principal, perm.type, perm.capability, l10nId);
|
||||
this._permissions.set(p.origin, p);
|
||||
},
|
||||
|
@ -250,6 +289,7 @@ var gSitePermissionsManager = {
|
|||
},
|
||||
|
||||
_createPermissionListItem(permission) {
|
||||
let width = (permission.type == "autoplay-media") ? "75" : "50";
|
||||
let richlistitem = document.createXULElement("richlistitem");
|
||||
richlistitem.setAttribute("origin", permission.origin);
|
||||
let row = document.createXULElement("hbox");
|
||||
|
@ -258,14 +298,14 @@ var gSitePermissionsManager = {
|
|||
let hbox = document.createXULElement("hbox");
|
||||
let website = document.createXULElement("label");
|
||||
website.setAttribute("value", permission.origin);
|
||||
website.setAttribute("width", "50");
|
||||
website.setAttribute("width", width);
|
||||
hbox.setAttribute("class", "website-name");
|
||||
hbox.setAttribute("flex", "3");
|
||||
hbox.appendChild(website);
|
||||
|
||||
let menulist = document.createXULElement("menulist");
|
||||
menulist.setAttribute("flex", "1");
|
||||
menulist.setAttribute("width", "50");
|
||||
menulist.setAttribute("width", width);
|
||||
menulist.setAttribute("class", "website-status");
|
||||
let states = SitePermissions.getAvailableStates(permission.type);
|
||||
for (let state of states) {
|
||||
|
@ -279,7 +319,7 @@ var gSitePermissionsManager = {
|
|||
continue;
|
||||
}
|
||||
let m = menulist.appendItem(undefined, state);
|
||||
document.l10n.setAttributes(m, this._getCapabilityString(state));
|
||||
document.l10n.setAttributes(m, this._getCapabilityString(permission.type, state));
|
||||
}
|
||||
menulist.value = permission.capability;
|
||||
|
||||
|
@ -360,7 +400,7 @@ var gSitePermissionsManager = {
|
|||
if (p.capability == capability)
|
||||
return;
|
||||
p.capability = capability;
|
||||
p.l10nId = this._getCapabilityString(capability);
|
||||
p.l10nId = this._getCapabilityString(perm.type, perm.capability);
|
||||
this._permissionsToChange.set(p.origin, p);
|
||||
|
||||
// enable "remove all" button as needed
|
||||
|
@ -418,6 +458,23 @@ var gSitePermissionsManager = {
|
|||
this._setRemoveButtonState();
|
||||
},
|
||||
|
||||
buildAutoplayMenulist() {
|
||||
let menulist = document.createXULElement("menulist");
|
||||
let states = SitePermissions.getAvailableStates("autoplay-media");
|
||||
for (let state of states) {
|
||||
let m = menulist.appendItem(undefined, state);
|
||||
document.l10n.setAttributes(m, this._getCapabilityString("autoplay-media", state));
|
||||
}
|
||||
|
||||
menulist.value = SitePermissions.getDefault("autoplay-media");
|
||||
|
||||
menulist.addEventListener("select", () => {
|
||||
SitePermissions.setDefault("autoplay-media", Number(menulist.value));
|
||||
});
|
||||
|
||||
document.getElementById("setAutoplayPref").appendChild(menulist);
|
||||
},
|
||||
|
||||
_sortPermissions(list, frag, column) {
|
||||
let sortDirection;
|
||||
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
</keyset>
|
||||
|
||||
<vbox class="contentPane">
|
||||
|
||||
<hbox align="center" id="setAutoplayPref" hidden="true">
|
||||
<label data-l10n-id="permissions-autoplay-menu"/>
|
||||
</hbox>
|
||||
<description id="permissionsText" control="url"/>
|
||||
<separator class="thin"/>
|
||||
<hbox align="start">
|
||||
|
|
|
@ -46,9 +46,18 @@ permissions-button-ok =
|
|||
.label = Save Changes
|
||||
.accesskey = S
|
||||
|
||||
permissions-autoplay-menu = Default for all websites:
|
||||
|
||||
permissions-searchbox =
|
||||
.placeholder = Search Website
|
||||
|
||||
permissions-capabilities-autoplay-allow =
|
||||
.label = Allow Audio and Video
|
||||
permissions-capabilities-autoplay-block =
|
||||
.label = Block Audio
|
||||
permissions-capabilities-autoplay-blockall =
|
||||
.label = Block Audio and Video
|
||||
|
||||
permissions-capabilities-allow =
|
||||
.label = Allow
|
||||
permissions-capabilities-block =
|
||||
|
@ -103,12 +112,12 @@ permissions-exceptions-addons-window =
|
|||
.style = { permissions-window.style }
|
||||
permissions-exceptions-addons-desc = You can specify which websites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow.
|
||||
|
||||
## Exceptions - Autoplay Media
|
||||
## Site Permissions - Autoplay
|
||||
|
||||
permissions-exceptions-autoplay-media-window2 =
|
||||
.title = Exceptions - Autoplay
|
||||
permissions-site-autoplay-window =
|
||||
.title = Settings - Autoplay
|
||||
.style = { permissions-window.style }
|
||||
permissions-exceptions-autoplay-media-desc2 = You can specify which websites are always or never allowed to autoplay media with sound. Type the address of the site you want to manage and then click Block or Allow.
|
||||
permissions-site-autoplay-desc = You can manage the sites that do not follow your default autoplay settings here.
|
||||
|
||||
## Site Permissions - Notifications
|
||||
|
||||
|
|
|
@ -887,7 +887,7 @@ content-blocking-cookies-label =
|
|||
.label = Cookies
|
||||
.accesskey = C
|
||||
|
||||
content-blocking-expand-section =
|
||||
content-blocking-expand-section =
|
||||
.tooltiptext = More information
|
||||
|
||||
# Cryptomining refers to using scripts on websites that can use a computer’s resources to mine cryptocurrency without a user’s knowledge.
|
||||
|
@ -936,13 +936,11 @@ permissions-notification-pause =
|
|||
.label = Pause notifications until { -brand-short-name } restarts
|
||||
.accesskey = n
|
||||
|
||||
permissions-block-autoplay-media2 =
|
||||
.label = Block websites from automatically playing sound
|
||||
.accesskey = B
|
||||
permissions-autoplay = Autoplay
|
||||
|
||||
permissions-block-autoplay-media-exceptions =
|
||||
.label = Exceptions…
|
||||
.accesskey = E
|
||||
permissions-autoplay-settings =
|
||||
.label = Settings…
|
||||
.accesskey = t
|
||||
|
||||
permissions-block-popups =
|
||||
.label = Block pop-up windows
|
||||
|
|
|
@ -28,6 +28,10 @@ state.multichoice.allow = Allow
|
|||
state.multichoice.allowForSession = Allow for Session
|
||||
state.multichoice.block = Block
|
||||
|
||||
state.multichoice.autoplayblock = Block Audio
|
||||
state.multichoice.autoplayblockall = Block Audio and Video
|
||||
state.multichoice.autoplayallow = Allow Audio and Video
|
||||
|
||||
permission.autoplay-media2.label = Autoplay sound
|
||||
permission.cookie.label = Set Cookies
|
||||
permission.desktop-notification3.label = Send Notifications
|
||||
|
|
|
@ -211,7 +211,7 @@ const GloballyBlockedPermissions = {
|
|||
for (let id of Object.keys(timeStamps)) {
|
||||
permissions.push({
|
||||
id,
|
||||
state: SitePermissions.BLOCK,
|
||||
state: gPermissionObject[id].getDefault(),
|
||||
scope: SitePermissions.SCOPE_GLOBAL,
|
||||
});
|
||||
}
|
||||
|
@ -246,6 +246,7 @@ var SitePermissions = {
|
|||
PROMPT: Services.perms.PROMPT_ACTION,
|
||||
ALLOW_COOKIES_FOR_SESSION: Ci.nsICookiePermission.ACCESS_SESSION,
|
||||
PROMPT_HIDE: Ci.nsIObjectLoadingContent.PLUGIN_PERMISSION_PROMPT_ACTION_QUIET,
|
||||
AUTOPLAY_BLOCKED_ALL: Ci.nsIAutoplay.BLOCKED_ALL,
|
||||
|
||||
// Permission scopes.
|
||||
SCOPE_REQUEST: "{SitePermissions.SCOPE_REQUEST}",
|
||||
|
@ -484,6 +485,23 @@ var SitePermissions = {
|
|||
return this._defaultPrefBranch.getIntPref(permissionID, this.UNKNOWN);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the default state of a particular permission.
|
||||
*
|
||||
* @param {string} permissionID
|
||||
* The ID to set the default for.
|
||||
*
|
||||
* @param {string} state
|
||||
* The state to set.
|
||||
*/
|
||||
setDefault(permissionID, state) {
|
||||
if (permissionID in gPermissionObject &&
|
||||
gPermissionObject[permissionID].setDefault) {
|
||||
return gPermissionObject[permissionID].setDefault(state);
|
||||
}
|
||||
let key = "permissions.default." + permissionID;
|
||||
return Services.prefs.setIntPref(key, state);
|
||||
},
|
||||
/**
|
||||
* Returns the state and scope of a particular permission for a given URI.
|
||||
*
|
||||
|
@ -770,7 +788,14 @@ var SitePermissions = {
|
|||
* @return {String|null} the localized label or null if an
|
||||
* unknown state was passed.
|
||||
*/
|
||||
getMultichoiceStateLabel(state) {
|
||||
getMultichoiceStateLabel(permissionID, state) {
|
||||
// If the permission has custom logic for getting its default value,
|
||||
// try that first.
|
||||
if (permissionID in gPermissionObject &&
|
||||
gPermissionObject[permissionID].getMultichoiceStateLabel) {
|
||||
return gPermissionObject[permissionID].getMultichoiceStateLabel(state);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case this.UNKNOWN:
|
||||
case this.PROMPT:
|
||||
|
@ -855,17 +880,42 @@ var gPermissionObject = {
|
|||
"autoplay-media": {
|
||||
exactHostMatch: true,
|
||||
getDefault() {
|
||||
let state = Services.prefs.getIntPref("media.autoplay.default",
|
||||
let pref = Services.prefs.getIntPref("media.autoplay.default",
|
||||
Ci.nsIAutoplay.BLOCKED);
|
||||
if (state == Ci.nsIAutoplay.ALLOWED) {
|
||||
if (pref == Ci.nsIAutoplay.ALLOWED) {
|
||||
return SitePermissions.ALLOW;
|
||||
} else if (state == Ci.nsIAutoplay.BLOCKED) {
|
||||
return SitePermissions.BLOCK;
|
||||
}
|
||||
return SitePermissions.UNKNOWN;
|
||||
if (pref == Ci.nsIAutoplay.BLOCKED_ALL) {
|
||||
return SitePermissions.AUTOPLAY_BLOCKED_ALL;
|
||||
}
|
||||
return SitePermissions.BLOCK;
|
||||
},
|
||||
setDefault(value) {
|
||||
let prefValue = Ci.nsIAutoplay.BLOCKED;
|
||||
if (value == SitePermissions.ALLOW) {
|
||||
prefValue = Ci.nsIAutoplay.ALLOWED;
|
||||
} else if (value == SitePermissions.AUTOPLAY_BLOCKED_ALL) {
|
||||
prefValue = Ci.nsIAutoplay.BLOCKED_ALL;
|
||||
}
|
||||
Services.prefs.setIntPref("media.autoplay.default", prefValue);
|
||||
},
|
||||
labelID: "autoplay-media2",
|
||||
states: [ SitePermissions.ALLOW, SitePermissions.BLOCK ],
|
||||
states: [
|
||||
SitePermissions.ALLOW,
|
||||
SitePermissions.BLOCK,
|
||||
SitePermissions.AUTOPLAY_BLOCKED_ALL,
|
||||
],
|
||||
getMultichoiceStateLabel(state) {
|
||||
switch (state) {
|
||||
case SitePermissions.AUTOPLAY_BLOCKED_ALL:
|
||||
return gStringBundle.GetStringFromName("state.multichoice.autoplayblockall");
|
||||
case SitePermissions.BLOCK:
|
||||
return gStringBundle.GetStringFromName("state.multichoice.autoplayblock");
|
||||
case SitePermissions.ALLOW:
|
||||
return gStringBundle.GetStringFromName("state.multichoice.autoplayallow");
|
||||
}
|
||||
throw new Error(`Unkown state: ${state}`);
|
||||
},
|
||||
},
|
||||
|
||||
"image": {
|
||||
|
|
|
@ -82,6 +82,10 @@
|
|||
list-style-image: url(chrome://browser/skin/notification-icons/desktop-notification.svg);
|
||||
}
|
||||
|
||||
.autoplay-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media-detailed.svg);
|
||||
}
|
||||
|
||||
.midi-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-icons/midi.svg);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
|
||||
mozilla::LazyLogModule gAutoplayPermissionLog("Autoplay");
|
||||
|
||||
|
@ -63,18 +65,18 @@ static bool IsActivelyCapturingOrHasAPermission(nsPIDOMWindowInner* aWindow) {
|
|||
NS_LITERAL_CSTRING("screen")));
|
||||
}
|
||||
|
||||
static bool IsSiteInAutoplayWhiteList(const Document* aDocument) {
|
||||
return aDocument ? nsContentUtils::IsExactSitePermAllow(
|
||||
aDocument->NodePrincipal(),
|
||||
NS_LITERAL_CSTRING("autoplay-media"))
|
||||
: false;
|
||||
}
|
||||
static uint32_t SiteAutoplayPerm(const Document* aDocument) {
|
||||
nsIPrincipal* principal = aDocument->NodePrincipal();
|
||||
if (!principal) {
|
||||
return nsIPermissionManager::DENY_ACTION;
|
||||
}
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
NS_ENSURE_TRUE(permMgr, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
static bool IsSiteInAutoplayBlackList(const Document* aDocument) {
|
||||
return aDocument ? nsContentUtils::IsExactSitePermDeny(
|
||||
aDocument->NodePrincipal(),
|
||||
NS_LITERAL_CSTRING("autoplay-media"))
|
||||
: false;
|
||||
uint32_t perm;
|
||||
nsresult rv = permMgr->TestExactPermissionFromPrincipal(principal, NS_LITERAL_CSTRING("autoplay-media"), &perm);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
return perm;
|
||||
}
|
||||
|
||||
static bool IsWindowAllowedToPlay(nsPIDOMWindowInner* aWindow) {
|
||||
|
@ -119,25 +121,24 @@ static bool IsWindowAllowedToPlay(nsPIDOMWindowInner* aWindow) {
|
|||
static uint32_t DefaultAutoplayBehaviour() {
|
||||
int prefValue =
|
||||
Preferences::GetInt("media.autoplay.default", nsIAutoplay::ALLOWED);
|
||||
if (prefValue < nsIAutoplay::ALLOWED || prefValue > nsIAutoplay::BLOCKED) {
|
||||
// Invalid pref values are just converted to BLOCKED.
|
||||
return nsIAutoplay::BLOCKED;
|
||||
if (prefValue == nsIAutoplay::ALLOWED) {
|
||||
return nsIAutoplay::ALLOWED;
|
||||
}
|
||||
return prefValue;
|
||||
if (prefValue == nsIAutoplay::BLOCKED_ALL) {
|
||||
return nsIAutoplay::BLOCKED_ALL;
|
||||
}
|
||||
return nsIAutoplay::BLOCKED;
|
||||
}
|
||||
|
||||
static bool IsMediaElementAllowedToPlay(const HTMLMediaElement& aElement) {
|
||||
const bool isAllowedMuted =
|
||||
Preferences::GetBool("media.autoplay.allow-muted", true);
|
||||
if ((aElement.Volume() == 0.0 || aElement.Muted()) && isAllowedMuted) {
|
||||
AUTOPLAY_LOG("Allow muted media %p to autoplay.", &aElement);
|
||||
static bool IsMediaElementInaudible(const HTMLMediaElement& aElement) {
|
||||
if (aElement.Volume() == 0.0 || aElement.Muted()) {
|
||||
AUTOPLAY_LOG("Media %p is muted.", &aElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aElement.HasAudio() &&
|
||||
aElement.ReadyState() >= HTMLMediaElement_Binding::HAVE_METADATA &&
|
||||
isAllowedMuted) {
|
||||
AUTOPLAY_LOG("Allow media %p without audio track to autoplay", &aElement);
|
||||
aElement.ReadyState() >= HTMLMediaElement_Binding::HAVE_METADATA) {
|
||||
AUTOPLAY_LOG("Media %p has no audio track", &aElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -153,14 +154,13 @@ static bool IsAudioContextAllowedToPlay(const AudioContext& aContext) {
|
|||
static bool IsEnableBlockingWebAudioByUserGesturePolicy() {
|
||||
return DefaultAutoplayBehaviour() != nsIAutoplay::ALLOWED &&
|
||||
Preferences::GetBool("media.autoplay.block-webaudio", false) &&
|
||||
Preferences::GetBool("media.autoplay.enabled.user-gestures-needed",
|
||||
false);
|
||||
StaticPrefs::MediaAutoplayUserGesturesNeeded();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool AutoplayPolicy::WouldBeAllowedToPlayIfAutoplayDisabled(
|
||||
const HTMLMediaElement& aElement) {
|
||||
return IsMediaElementAllowedToPlay(aElement) ||
|
||||
return IsMediaElementInaudible(aElement) ||
|
||||
IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow());
|
||||
}
|
||||
|
||||
|
@ -170,44 +170,54 @@ bool AutoplayPolicy::WouldBeAllowedToPlayIfAutoplayDisabled(
|
|||
return IsAudioContextAllowedToPlay(aContext);
|
||||
}
|
||||
|
||||
static bool IsAllowedToPlayInternal(const HTMLMediaElement& aElement) {
|
||||
/**
|
||||
* The autoplay checking has 4 different phases,
|
||||
* 1. check whether media element itself meets the autoplay condition
|
||||
* 2. check whethr the site is in the autoplay whitelist
|
||||
* 3. check global autoplay setting and check wether the site is in the
|
||||
* autoplay blacklist.
|
||||
* 4. check whether media is allowed under current blocking model
|
||||
* (click-to-play or user-gesture-activation)
|
||||
*/
|
||||
if (IsMediaElementAllowedToPlay(aElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Document* approver = ApproverDocOf(*aElement.OwnerDoc());
|
||||
if (IsSiteInAutoplayWhiteList(approver)) {
|
||||
AUTOPLAY_LOG(
|
||||
"Allow autoplay as document has permanent autoplay permission.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DefaultAutoplayBehaviour() == nsIAutoplay::ALLOWED &&
|
||||
!(IsSiteInAutoplayBlackList(approver) &&
|
||||
StaticPrefs::MediaAutoplayBlackListOverrideDefault())) {
|
||||
AUTOPLAY_LOG(
|
||||
"Allow autoplay as global autoplay setting is allowing autoplay by "
|
||||
"default.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed",
|
||||
false)) {
|
||||
// If element is blessed, it would always be allowed to play().
|
||||
return aElement.IsBlessed() || EventStateManager::IsHandlingUserInput();
|
||||
static bool IsAllowedToPlayByBlockingModel(const HTMLMediaElement& aElement) {
|
||||
if (!StaticPrefs::MediaAutoplayUserGesturesNeeded()) {
|
||||
// If element is blessed, it would always be allowed to play().
|
||||
return aElement.IsBlessed() || EventStateManager::IsHandlingUserInput();
|
||||
}
|
||||
return IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow());
|
||||
}
|
||||
|
||||
static bool IsAllowedToPlayInternal(const HTMLMediaElement& aElement) {
|
||||
Document* approver = ApproverDocOf(*aElement.OwnerDoc());
|
||||
|
||||
bool isInaudible = IsMediaElementInaudible(aElement);
|
||||
bool isUsingAutoplayModel = IsAllowedToPlayByBlockingModel(aElement);
|
||||
|
||||
uint32_t defaultBehaviour = DefaultAutoplayBehaviour();
|
||||
uint32_t sitePermission = SiteAutoplayPerm(approver);
|
||||
|
||||
AUTOPLAY_LOG("IsAllowedToPlayInternal, isInaudible=%d,"
|
||||
"isUsingAutoplayModel=%d, sitePermission=%d, defaultBehaviour=%d",
|
||||
isInaudible, isUsingAutoplayModel, sitePermission, defaultBehaviour);
|
||||
|
||||
// For site permissions we store permissionManager values except
|
||||
// for BLOCKED_ALL, for the default pref values we store
|
||||
// nsIAutoplay values.
|
||||
if (sitePermission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sitePermission == nsIPermissionManager::DENY_ACTION) {
|
||||
return isInaudible || isUsingAutoplayModel;
|
||||
}
|
||||
|
||||
if (sitePermission == nsIAutoplay::BLOCKED_ALL) {
|
||||
return isUsingAutoplayModel;
|
||||
}
|
||||
|
||||
if (defaultBehaviour == nsIAutoplay::ALLOWED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (defaultBehaviour == nsIAutoplay::BLOCKED) {
|
||||
return isInaudible || isUsingAutoplayModel;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(defaultBehaviour == nsIAutoplay::BLOCKED_ALL);
|
||||
return isUsingAutoplayModel;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool AutoplayPolicy::IsAllowedToPlay(const HTMLMediaElement& aElement) {
|
||||
const bool result = IsAllowedToPlayInternal(aElement);
|
||||
|
@ -235,14 +245,17 @@ bool AutoplayPolicy::IsAllowedToPlay(const AudioContext& aContext) {
|
|||
Document* approver = aContext.GetParentObject()
|
||||
? ApproverDocOf(*(window->GetExtantDoc()))
|
||||
: nullptr;
|
||||
if (IsSiteInAutoplayWhiteList(approver)) {
|
||||
uint32_t sitePermission = SiteAutoplayPerm(approver);
|
||||
|
||||
if (sitePermission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
AUTOPLAY_LOG(
|
||||
"Allow autoplay as document has permanent autoplay permission.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DefaultAutoplayBehaviour() == nsIAutoplay::ALLOWED &&
|
||||
!IsSiteInAutoplayBlackList(approver)) {
|
||||
sitePermission != nsIPermissionManager::DENY_ACTION &&
|
||||
sitePermission != nsIAutoplay::BLOCKED_ALL) {
|
||||
AUTOPLAY_LOG(
|
||||
"Allow autoplay as global autoplay setting is allowing autoplay by "
|
||||
"default.");
|
||||
|
@ -263,7 +276,7 @@ DocumentAutoplayPolicy AutoplayPolicy::IsAllowedToPlay(
|
|||
return DocumentAutoplayPolicy::Allowed;
|
||||
}
|
||||
|
||||
if (StaticPrefs::MediaAutoplayAllowMuted()) {
|
||||
if (DefaultAutoplayBehaviour() == nsIAutoplay::BLOCKED) {
|
||||
return DocumentAutoplayPolicy::Allowed_muted;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,4 +13,5 @@ interface nsIAutoplay : nsISupports
|
|||
*/
|
||||
const uint32_t ALLOWED = 0;
|
||||
const uint32_t BLOCKED = 1;
|
||||
const uint32_t BLOCKED_ALL = 5;
|
||||
};
|
||||
|
|
|
@ -4722,6 +4722,13 @@ VARCACHE_PREF(
|
|||
// These prefs use camel case instead of snake case for the getter because one
|
||||
// reviewer had an unshakeable preference for that. Who could that be?
|
||||
|
||||
VARCACHE_PREF(
|
||||
Live,
|
||||
"media.autoplay.enabled.user-gestures-needed",
|
||||
MediaAutoplayUserGesturesNeeded,
|
||||
bool, false
|
||||
)
|
||||
|
||||
VARCACHE_PREF(
|
||||
Live,
|
||||
"media.autoplay.allow-muted",
|
||||
|
|
|
@ -545,9 +545,6 @@ pref("media.autoplay.default", 0);
|
|||
// By default, don't block WebAudio from playing automatically.
|
||||
pref("media.autoplay.block-webaudio", false);
|
||||
|
||||
// By default, don't block muted media from playing automatically.
|
||||
pref("media.autoplay.allow-muted", true);
|
||||
|
||||
// By default, don't block the media from extension background script.
|
||||
pref("media.autoplay.allow-extension-background-pages", true);
|
||||
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
|
||||
|
||||
function setupTestPreferences(isAllowedAutoplay, isAllowedMuted) {
|
||||
const autoplayDefault = isAllowedAutoplay ?
|
||||
SpecialPowers.Ci.nsIAutoplay.ALLOWED : SpecialPowers.Ci.nsIAutoplay.BLOCKED;
|
||||
let autoplayDefault = SpecialPowers.Ci.nsIAutoplay.ALLOWED;
|
||||
if (!isAllowedAutoplay) {
|
||||
autoplayDefault = isAllowedMuted ? SpecialPowers.Ci.nsIAutoplay.BLOCKED
|
||||
: SpecialPowers.Ci.nsIAutoplay.BLOCKED_ALL;
|
||||
}
|
||||
return SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.media.autoplay.autoplay-policy-api", true],
|
||||
["media.autoplay.default", autoplayDefault],
|
||||
["media.autoplay.enabled.user-gestures-needed", true],
|
||||
["media.autoplay.allow-muted", isAllowedMuted],
|
||||
]});
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче