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:
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();
}
},