зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1642804 - Make sure to show notification silencing option in private browsing WebRTC screen sharing panel. r=pbz
Differential Revision: https://phabricator.services.mozilla.com/D78120
This commit is contained in:
Родитель
d7e086f85f
Коммит
4d269fae1d
|
@ -1121,7 +1121,8 @@ function prompt(aActor, aBrowser, aRequest) {
|
|||
if (shouldShowAlwaysRemember()) {
|
||||
// Disable the permanent 'Allow' action if the connection isn't secure, or for
|
||||
// screen/audio sharing (because we can't guess which window the user wants to
|
||||
// share without prompting).
|
||||
// share without prompting). Note that we never enter this block for private
|
||||
// browsing windows.
|
||||
let reasonForNoPermanentAllow = "";
|
||||
if (sharingScreen) {
|
||||
reasonForNoPermanentAllow =
|
||||
|
@ -1134,38 +1135,41 @@ function prompt(aActor, aBrowser, aRequest) {
|
|||
"getUserMedia.reasonForNoPermanentAllow.insecure";
|
||||
}
|
||||
|
||||
if (notificationSilencingEnabled && sharingScreen) {
|
||||
let [
|
||||
silenceNotifications,
|
||||
silenceNotificationsWarning,
|
||||
] = localization.formatMessagesSync([
|
||||
{ id: "popup-silence-notifications-checkbox" },
|
||||
{ id: "popup-silence-notifications-checkbox-warning" },
|
||||
]);
|
||||
options.checkbox = {
|
||||
label: stringBundle.getString("getUserMedia.remember"),
|
||||
checked: principal.isAddonOrExpandedAddonPrincipal,
|
||||
checkedState: reasonForNoPermanentAllow
|
||||
? {
|
||||
disableMainAction: true,
|
||||
warningLabel: stringBundle.getFormattedString(
|
||||
reasonForNoPermanentAllow,
|
||||
[productName]
|
||||
),
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
options.checkbox = {
|
||||
label: silenceNotifications.value,
|
||||
checked: false,
|
||||
checkedState: {
|
||||
disableMainAction: false,
|
||||
warningLabel: silenceNotificationsWarning.value,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
options.checkbox = {
|
||||
label: stringBundle.getString("getUserMedia.remember"),
|
||||
checked: principal.isAddonOrExpandedAddonPrincipal,
|
||||
checkedState: reasonForNoPermanentAllow
|
||||
? {
|
||||
disableMainAction: true,
|
||||
warningLabel: stringBundle.getFormattedString(
|
||||
reasonForNoPermanentAllow,
|
||||
[productName]
|
||||
),
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
// If the notification silencing feature is enabled and we're sharing a
|
||||
// screen, then the checkbox for the permission panel is what controls
|
||||
// notification silencing.
|
||||
if (notificationSilencingEnabled && sharingScreen) {
|
||||
let [
|
||||
silenceNotifications,
|
||||
silenceNotificationsWarning,
|
||||
] = localization.formatMessagesSync([
|
||||
{ id: "popup-silence-notifications-checkbox" },
|
||||
{ id: "popup-silence-notifications-checkbox-warning" },
|
||||
]);
|
||||
|
||||
options.checkbox = {
|
||||
label: silenceNotifications.value,
|
||||
checked: false,
|
||||
checkedState: {
|
||||
disableMainAction: false,
|
||||
warningLabel: silenceNotificationsWarning.value,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let iconType = "Devices";
|
||||
|
|
|
@ -32,6 +32,7 @@ skip-if = (os == 'linux') # Bug 1503991
|
|||
[browser_devices_get_user_media_unprompted_access_tear_off_tab.js]
|
||||
skip-if = (os == "win" && bits == 64) # win8: bug 1334752
|
||||
[browser_devices_get_user_media_unprompted_access_queue_request.js]
|
||||
[browser_notification_silencing.js]
|
||||
[browser_tab_switch_warning.js]
|
||||
[browser_webrtc_hooks.js]
|
||||
[browser_devices_get_user_media_queue_request.js]
|
||||
|
|
|
@ -100,7 +100,13 @@ async function promptNoDelegateScreenSharing(aThirdPartyOrgin) {
|
|||
// The 'Remember this decision' checkbox is hidden.
|
||||
const checkbox = notification.checkbox;
|
||||
ok(!!checkbox, "checkbox is present");
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
|
||||
if (ALLOW_SILENCING_NOTIFICATIONS) {
|
||||
ok(!checkbox.hidden, "Notification silencing checkbox is visible");
|
||||
} else {
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
}
|
||||
|
||||
ok(!checkbox.checked, "checkbox not checked");
|
||||
|
||||
// Check the label of the notification should be the first party
|
||||
|
@ -663,7 +669,6 @@ var gTests = [
|
|||
await promptNoDelegate("test2.example.com");
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc:
|
||||
"Change location, prompt and display both first party and third party origin when sharing screen in unsafe permission delegation",
|
||||
|
@ -675,7 +680,6 @@ var gTests = [
|
|||
await promptNoDelegateScreenSharing("test2.example.com");
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc:
|
||||
"Prompt and display both first party and third party origin and temporary deny in frame does not change permission scope",
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_ROOT = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content/",
|
||||
"https://example.com/"
|
||||
);
|
||||
const TEST_PAGE = TEST_ROOT + "get_user_media.html";
|
||||
|
||||
/**
|
||||
* Tests that the screen / window sharing permission popup offers the ability
|
||||
* for users to silence DOM notifications while sharing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper function that exercises a specific browser to test whether or not the
|
||||
* user can silence notifications via the display sharing permission panel.
|
||||
*
|
||||
* First, we ensure that notification silencing is disabled by default. Then, we
|
||||
* request screen sharing from the browser, and check the checkbox that
|
||||
* silences notifications. Once screen sharing is established, then we ensure
|
||||
* that notification silencing is enabled. Then we stop sharing, and ensure that
|
||||
* notification silencing is disabled again.
|
||||
*
|
||||
* @param {<xul:browser>} aBrowser - The window to run the test on. This browser
|
||||
* should have TEST_PAGE loaded.
|
||||
* @return Promise
|
||||
* @resolves undefined - When the test on the browser is complete.
|
||||
*/
|
||||
async function testNotificationSilencing(aBrowser) {
|
||||
let hasIndicator = Services.wm
|
||||
.getEnumerator("Browser:WebRTCGlobalIndicator")
|
||||
.hasMoreElements();
|
||||
|
||||
let window = aBrowser.ownerGlobal;
|
||||
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
Assert.ok(alertsService, "Alerts Service implements nsIAlertsDoNotDisturb");
|
||||
Assert.ok(
|
||||
!alertsService.suppressForScreenSharing,
|
||||
"Should not be silencing notifications to start."
|
||||
);
|
||||
|
||||
let observerPromise = expectObserverCalled(
|
||||
"getUserMedia:request",
|
||||
1,
|
||||
aBrowser
|
||||
);
|
||||
let promise = promisePopupNotificationShown(
|
||||
"webRTC-shareDevices",
|
||||
null,
|
||||
window
|
||||
);
|
||||
let indicatorPromise = hasIndicator
|
||||
? Promise.resolve()
|
||||
: promiseIndicatorWindow();
|
||||
await promiseRequestDevice(false, true, null, "screen", aBrowser);
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
checkDeviceSelectors(false, false, true, window);
|
||||
|
||||
let document = window.document;
|
||||
|
||||
// Select one of the windows / screens. It doesn't really matter which.
|
||||
let menulist = document.getElementById("webRTC-selectWindow-menulist");
|
||||
menulist.getItemAtIndex(menulist.itemCount - 1).doCommand();
|
||||
|
||||
let notification = window.PopupNotifications.panel.firstElementChild;
|
||||
Assert.ok(
|
||||
notification.hasAttribute("warninghidden"),
|
||||
"Notification silencing warning message is hidden by default"
|
||||
);
|
||||
|
||||
let checkbox = notification.checkbox;
|
||||
Assert.ok(!!checkbox, "Notification silencing checkbox is present");
|
||||
Assert.ok(!checkbox.checked, "checkbox is not checked by default");
|
||||
checkbox.click();
|
||||
Assert.ok(checkbox.checked, "checkbox now checked");
|
||||
// The orginal behaviour of the checkbox disabled the Allow button. Let's
|
||||
// make sure we're not still doing that.
|
||||
Assert.ok(!notification.button.disabled, "Allow button is not disabled");
|
||||
Assert.ok(
|
||||
!notification.hasAttribute("warninghidden"),
|
||||
"warning message is shown"
|
||||
);
|
||||
|
||||
let observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:response:allow",
|
||||
1,
|
||||
aBrowser
|
||||
);
|
||||
let observerPromise2 = expectObserverCalled(
|
||||
"recording-device-events",
|
||||
1,
|
||||
aBrowser
|
||||
);
|
||||
await promiseMessage(
|
||||
"ok",
|
||||
() => {
|
||||
notification.button.click();
|
||||
},
|
||||
1,
|
||||
aBrowser
|
||||
);
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
let indicator = await indicatorPromise;
|
||||
|
||||
Assert.ok(
|
||||
alertsService.suppressForScreenSharing,
|
||||
"Should now be silencing notifications"
|
||||
);
|
||||
|
||||
let indicatorClosedPromise = hasIndicator
|
||||
? Promise.resolve()
|
||||
: BrowserTestUtils.domWindowClosed(indicator);
|
||||
|
||||
await stopSharing("screen", true, aBrowser, window);
|
||||
await indicatorClosedPromise;
|
||||
|
||||
Assert.ok(
|
||||
!alertsService.suppressForScreenSharing,
|
||||
"Should no longer be silencing notifications"
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
// Set prefs so that permissions prompts are shown and loopback devices
|
||||
// are not used. To test the chrome we want prompts to be shown, and
|
||||
// these tests are flakey when using loopback devices (though it would
|
||||
// be desirable to make them work with loopback in future). See bug 1643711.
|
||||
let prefs = [
|
||||
[PREF_PERMISSION_FAKE, true],
|
||||
[PREF_AUDIO_LOOPBACK, ""],
|
||||
[PREF_VIDEO_LOOPBACK, ""],
|
||||
[PREF_FAKE_STREAMS, true],
|
||||
[PREF_FOCUS_SOURCE, false],
|
||||
];
|
||||
|
||||
await SpecialPowers.pushPrefEnv({ set: prefs });
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests notification silencing in a normal browser window.
|
||||
*/
|
||||
add_task(async function testNormalWindow() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: TEST_PAGE,
|
||||
},
|
||||
async browser => {
|
||||
await testNotificationSilencing(browser);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests notification silencing in a private browser window.
|
||||
*/
|
||||
add_task(async function testPrivateWindow() {
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser: privateWindow.gBrowser,
|
||||
url: TEST_PAGE,
|
||||
},
|
||||
async browser => {
|
||||
await testNotificationSilencing(browser);
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(privateWindow);
|
||||
});
|
|
@ -321,46 +321,50 @@ function expectObserverCalledOnClose(
|
|||
});
|
||||
}
|
||||
|
||||
function promiseMessage(aMessage, aAction, aCount = 1) {
|
||||
let promise = ContentTask.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
[aMessage, aCount],
|
||||
async function([expectedMessage, expectedCount]) {
|
||||
return new Promise(resolve => {
|
||||
function listenForMessage({ data }) {
|
||||
if (
|
||||
(!expectedMessage || data == expectedMessage) &&
|
||||
--expectedCount == 0
|
||||
) {
|
||||
content.removeEventListener("message", listenForMessage);
|
||||
resolve(data);
|
||||
}
|
||||
function promiseMessage(
|
||||
aMessage,
|
||||
aAction,
|
||||
aCount = 1,
|
||||
browser = gBrowser.selectedBrowser
|
||||
) {
|
||||
let promise = ContentTask.spawn(browser, [aMessage, aCount], async function([
|
||||
expectedMessage,
|
||||
expectedCount,
|
||||
]) {
|
||||
return new Promise(resolve => {
|
||||
function listenForMessage({ data }) {
|
||||
if (
|
||||
(!expectedMessage || data == expectedMessage) &&
|
||||
--expectedCount == 0
|
||||
) {
|
||||
content.removeEventListener("message", listenForMessage);
|
||||
resolve(data);
|
||||
}
|
||||
content.addEventListener("message", listenForMessage);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
content.addEventListener("message", listenForMessage);
|
||||
});
|
||||
});
|
||||
if (aAction) {
|
||||
aAction();
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
function promisePopupNotificationShown(aName, aAction) {
|
||||
function promisePopupNotificationShown(aName, aAction, aWindow = window) {
|
||||
return new Promise(resolve => {
|
||||
// In case the global webrtc indicator has stolen focus (bug 1421724)
|
||||
window.focus();
|
||||
aWindow.focus();
|
||||
|
||||
PopupNotifications.panel.addEventListener(
|
||||
aWindow.PopupNotifications.panel.addEventListener(
|
||||
"popupshown",
|
||||
function() {
|
||||
ok(
|
||||
!!PopupNotifications.getNotification(aName),
|
||||
!!aWindow.PopupNotifications.getNotification(aName),
|
||||
aName + " notification shown"
|
||||
);
|
||||
ok(PopupNotifications.isPanelOpen, "notification panel open");
|
||||
ok(aWindow.PopupNotifications.isPanelOpen, "notification panel open");
|
||||
ok(
|
||||
!!PopupNotifications.panel.firstElementChild,
|
||||
!!aWindow.PopupNotifications.panel.firstElementChild,
|
||||
"notification panel populated"
|
||||
);
|
||||
|
||||
|
@ -511,22 +515,17 @@ async function getMediaCaptureState() {
|
|||
async function stopSharing(
|
||||
aType = "camera",
|
||||
aShouldKeepSharing = false,
|
||||
aFrameBC
|
||||
aFrameBC,
|
||||
aWindow = window
|
||||
) {
|
||||
// If the observers are listening to other frames, listen for a notification
|
||||
// on the right subframe.
|
||||
let frameBCToObserve;
|
||||
if (gBrowserContextsToObserve.length > 1) {
|
||||
frameBCToObserve = aFrameBC;
|
||||
}
|
||||
|
||||
let promiseRecordingEvent = expectObserverCalled(
|
||||
"recording-device-events",
|
||||
1,
|
||||
frameBCToObserve
|
||||
aFrameBC
|
||||
);
|
||||
gIdentityHandler._identityBox.click();
|
||||
let permissions = document.getElementById("identity-popup-permission-list");
|
||||
aWindow.gIdentityHandler._identityBox.click();
|
||||
let doc = aWindow.document;
|
||||
let permissions = doc.getElementById("identity-popup-permission-list");
|
||||
let cancelButton = permissions.querySelector(
|
||||
".identity-popup-permission-icon." +
|
||||
aType +
|
||||
|
@ -536,7 +535,7 @@ async function stopSharing(
|
|||
let observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:revoke",
|
||||
1,
|
||||
frameBCToObserve
|
||||
aFrameBC
|
||||
);
|
||||
|
||||
// If we are stopping screen sharing and expect to still have another stream,
|
||||
|
@ -546,12 +545,13 @@ async function stopSharing(
|
|||
observerPromise2 = expectObserverCalled(
|
||||
"recording-window-ended",
|
||||
1,
|
||||
frameBCToObserve
|
||||
aFrameBC
|
||||
);
|
||||
}
|
||||
|
||||
cancelButton.click();
|
||||
gIdentityHandler._identityPopup.hidden = true;
|
||||
aWindow.gIdentityHandler._identityPopup.hidden = true;
|
||||
|
||||
await promiseRecordingEvent;
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
|
@ -660,7 +660,8 @@ async function reloadAndAssertClosedStreams() {
|
|||
await checkNotSharing();
|
||||
}
|
||||
|
||||
function checkDeviceSelectors(aAudio, aVideo, aScreen) {
|
||||
function checkDeviceSelectors(aAudio, aVideo, aScreen, aWindow = window) {
|
||||
let document = aWindow.document;
|
||||
let micSelector = document.getElementById("webRTC-selectMicrophone");
|
||||
if (aAudio) {
|
||||
ok(!micSelector.hidden, "microphone selector visible");
|
||||
|
@ -889,7 +890,7 @@ async function runTests(tests, options = {}) {
|
|||
// Set prefs so that permissions prompts are shown and loopback devices
|
||||
// are not used. To test the chrome we want prompts to be shown, and
|
||||
// these tests are flakey when using loopback devices (though it would
|
||||
// be desirable to make them work with loopback in future).
|
||||
// be desirable to make them work with loopback in future). See bug 1643711.
|
||||
let prefs = [
|
||||
[PREF_PERMISSION_FAKE, true],
|
||||
[PREF_AUDIO_LOOPBACK, ""],
|
||||
|
|
Загрузка…
Ссылка в новой задаче