tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 27dd8169b11e76e1011ce02f0392c0b98c8a607a
parent 2cb4fb98f62f8cc0e143c4df63a6fdcee9555d8f
Author: Nikki Sharpley <nsharpley@mozilla.com>
Date:   Tue,  6 Jan 2026 15:50:10 +0000

Bug 1997852 - If a permission access window is displayed, still allow other view to be selected r=tabbrowser-reviewers,kcochrane

Differential Revision: https://phabricator.services.mozilla.com/D276231

Diffstat:
Mbrowser/base/content/test/webrtc/browser_devices_get_user_media.js | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/modules/PopupNotifications.sys.mjs | 3++-
2 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/browser/base/content/test/webrtc/browser_devices_get_user_media.js b/browser/base/content/test/webrtc/browser_devices_get_user_media.js @@ -16,6 +16,32 @@ function clearPermissions() { PermissionTestUtils.remove(gBrowser.contentPrincipal, "microphone"); } +async function addTabAndLoadBrowser() { + const tab = BrowserTestUtils.addTab(gBrowser, "https://example.com"); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + return tab; +} + +async function checkSplitViewPanelVisible(tab, isVisible) { + const panel = document.getElementById(tab.linkedPanel); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => panel.classList.contains("split-view-panel") == isVisible + ); + if (isVisible) { + Assert.ok( + gBrowser.splitViewBrowsers.includes(tab.linkedBrowser), + "Split view panel is active." + ); + } else { + Assert.ok( + !gBrowser.splitViewBrowsers.includes(tab.linkedBrowser), + "Split view panel is inactive." + ); + } +} + var gTests = [ { desc: "getUserMedia audio+video", @@ -146,6 +172,132 @@ var gTests = [ }, { + desc: "getUserMedia video only popup notification with split view", + run: async function checkVideoOnlyWithSplitView() { + const tab1 = gBrowser.selectedTab; + const tab2 = await addTabAndLoadBrowser(); + const urlbarButton = document.getElementById("split-view-button"); + + info("Activate split view."); + const splitView = gBrowser.addTabSplitView([tab1, tab2]); + for (const tab of splitView.tabs) { + await checkSplitViewPanelVisible(tab, true); + } + + info("Select tabs using tab panels."); + await SimpleTest.promiseFocus(tab1.linkedBrowser); + let panel = document.getElementById(tab1.linkedPanel); + Assert.ok( + panel.classList.contains("deck-selected"), + "First panel is selected." + ); + + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(false, true); + await promise; + await observerPromise; + Assert.ok( + PopupNotifications.getNotification("webRTC-shareDevices"), + "webRTC-shareDevices popup notification is present" + ); + + await SimpleTest.promiseFocus(tab2.linkedBrowser); + panel = document.getElementById(tab2.linkedPanel); + Assert.ok( + panel.classList.contains("deck-selected"), + "Second panel is selected." + ); + + // Notification should only be present on the splitview panel it affects + Assert.ok( + !PopupNotifications.getNotification("webRTC-shareDevices"), + "webRTC-shareDevices popup notification is not present" + ); + + info("Switch back to original split view tab."); + await BrowserTestUtils.switchTab(gBrowser, tab1); + for (const tab of splitView.tabs) { + await checkSplitViewPanelVisible(tab, true); + } + + // Check we are able to go back to the original splitview panel and see notification + Assert.ok( + PopupNotifications.getNotification("webRTC-shareDevices"), + "webRTC-shareDevices popup notification is present" + ); + + info("Select tabs using tabs"); + await BrowserTestUtils.switchTab(gBrowser, tab2); + panel = document.getElementById(tab2.linkedPanel); + Assert.ok( + panel.classList.contains("deck-selected"), + "Second panel is selected." + ); + + Assert.ok( + !PopupNotifications.getNotification("webRTC-shareDevices"), + "webRTC-shareDevices popup notification is not present" + ); + + info("Switch back to original split view tab."); + await BrowserTestUtils.switchTab(gBrowser, tab1); + for (const tab of splitView.tabs) { + await checkSplitViewPanelVisible(tab, true); + } + + Assert.ok( + PopupNotifications.getNotification("webRTC-shareDevices"), + "webRTC-shareDevices popup notification is present" + ); + + await BrowserTestUtils.waitForMutationCondition( + PopupNotifications.panel, + { childList: true }, + () => PopupNotifications.panel?.firstElementChild + ); + await BrowserTestUtils.waitForMutationCondition( + PopupNotifications.panel.firstElementChild, + { childList: true }, + () => PopupNotifications.panel.firstElementChild?.button + ); + let indicator = promiseIndicatorWindow(); + let observerPromise1 = expectObserverCalled( + "getUserMedia:response:allow" + ); + let observerPromise2 = expectObserverCalled("recording-device-events"); + await promiseMessage("ok", () => { + PopupNotifications.panel.firstElementChild.button.click(); + }); + await observerPromise1; + await observerPromise2; + Assert.deepEqual( + await getMediaCaptureState(), + { video: true }, + "expected camera to be shared" + ); + + await indicator; + await checkSharingUI({ video: true }); + is(getPerm("microphone"), Services.perms.UNKNOWN_ACTION, "no mic once"); + is(getPerm("camera"), Services.perms.PROMPT_ACTION, "cam once"); + clearPermissions(); + await closeStream(); + + info("Remove the split view, keeping tabs intact."); + splitView.unsplitTabs(); + await checkSplitViewPanelVisible(tab1, false); + await checkSplitViewPanelVisible(tab2, false); + await BrowserTestUtils.waitForMutationCondition( + urlbarButton, + { attributes: true }, + () => BrowserTestUtils.isHidden(urlbarButton) + ); + BrowserTestUtils.removeTab(tab2); + }, + }, + + { desc: 'getUserMedia audio+video, user clicks "Don\'t Share"', run: async function checkDontShare() { let observerPromise = expectObserverCalled("getUserMedia:request"); diff --git a/toolkit/modules/PopupNotifications.sys.mjs b/toolkit/modules/PopupNotifications.sys.mjs @@ -928,7 +928,8 @@ PopupNotifications.prototype = { this.panel.firstElementChild && this.panel.firstElementChild.notification.browser; this.panel.hidePopup(); - if (browser) { + // Focus the browser if it's still selected by the time we dismiss. + if (browser && this.tabbrowser.selectedBrowser === browser) { browser.focus(); } },