tor-browser

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

commit 36d8a4108e1f0be382e56a30894f0355b9c36ed1
parent a7b1b356be396377b98cf8511a15ab2a82af6823
Author: Meg Viar <lmegviar@gmail.com>
Date:   Tue, 30 Sep 2025 15:50:54 +0000

Bug 1990947 - Allow changes to any of a list of prefs to dismiss an infobar r=omc-reviewers,jprickett

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

Diffstat:
Mbrowser/components/asrouter/content-src/schemas/MessagingExperiment.schema.json | 16++++++++++++++--
Mbrowser/components/asrouter/content-src/templates/CFR/templates/InfoBar.schema.json | 12++++++++++--
Mbrowser/components/asrouter/modules/InfoBar.sys.mjs | 45+++++++++++++++++++++++++++++----------------
Mbrowser/components/asrouter/tests/browser/browser_asrouter_infobar.js | 43+++++++++++++++++++++++++++++++++++++++++++
4 files changed, 96 insertions(+), 20 deletions(-)

diff --git a/browser/components/asrouter/content-src/schemas/MessagingExperiment.schema.json b/browser/components/asrouter/content-src/schemas/MessagingExperiment.schema.json @@ -646,8 +646,20 @@ "type": "boolean" }, "dismissOnPrefChange": { - "description": "If set, the name of a pref to observe. The infobar will automatically dismiss when this pref is set for the first time or when its value changes.", - "type": "string" + "description": "If set, one or more prefs to observe. The infobar will automatically dismiss when any of these prefs is set for the first time or when its value changes.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + ] }, "impression_action": { "oneOf": [ diff --git a/browser/components/asrouter/content-src/templates/CFR/templates/InfoBar.schema.json b/browser/components/asrouter/content-src/templates/CFR/templates/InfoBar.schema.json @@ -81,8 +81,16 @@ "type": "boolean" }, "dismissOnPrefChange": { - "description": "If set, the name of a pref to observe. The infobar will automatically dismiss when this pref is set for the first time or when its value changes.", - "type": "string" + "description": "If set, one or more prefs to observe. The infobar will automatically dismiss when any of these prefs is set for the first time or when its value changes.", + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + ] }, "impression_action": { "oneOf": [ diff --git a/browser/components/asrouter/modules/InfoBar.sys.mjs b/browser/components/asrouter/modules/InfoBar.sys.mjs @@ -34,8 +34,15 @@ class InfoBarNotification { this.infobarCallback = this.infobarCallback.bind(this); this.message = message; this.notification = null; - // If set, this is the pref to watch for changes to auto-dismiss the infobar. - this._dismissPref = message?.content?.dismissOnPrefChange || null; + const dismissPrefConfig = message?.content?.dismissOnPrefChange; + // If set, these are the prefs to watch for changes to auto-dismiss the infobar. + if (Array.isArray(dismissPrefConfig)) { + this._dismissPrefs = dismissPrefConfig; + } else if (dismissPrefConfig) { + this._dismissPrefs = [dismissPrefConfig]; + } else { + this._dismissPrefs = []; + } this._prefObserver = null; } @@ -397,11 +404,12 @@ class InfoBarNotification { } /** - * If content.dismissOnPrefChange is set, observe that pref and dismiss the - * infobar whenever it changes (including when it is set for the first time). + * If content.dismissOnPrefChange is set (string or array), observe those + * pref(s) and dismiss the infobar whenever any of them changes (including + * when it is set for the first time). */ _maybeAttachPrefObserver() { - if (!this._dismissPref || this._prefObserver) { + if (!this._dismissPrefs?.length || this._prefObserver) { return; } // Weak observer to avoid leaks. @@ -411,7 +419,7 @@ class InfoBarNotification { "nsISupportsWeakReference", ]), observe: (subject, topic, data) => { - if (topic === "nsPref:changed" && data === this._dismissPref) { + if (topic === "nsPref:changed" && this._dismissPrefs.includes(data)) { try { this.notification?.dismiss(); } catch (e) { @@ -421,27 +429,32 @@ class InfoBarNotification { }, }; try { - // Hold weak so we don't retain the infobar if something goes wrong. - Services.prefs.addObserver(this._dismissPref, this._prefObserver, true); + // Register each pref with a weak observer and ignore per-pref failures. + for (const pref of this._dismissPrefs) { + try { + Services.prefs.addObserver(pref, this._prefObserver, true); + } catch (_) {} + } } catch (e) { console.error( - `Failed to add prefs observer for ${this._dismissPref}:`, + "Failed to add prefs observer(s) for dismissOnPrefChange:", e ); } } _removePrefObserver() { - if (!this._dismissPref || !this._prefObserver) { + if (!this._dismissPrefs?.length || !this._prefObserver) { return; } - try { - Services.prefs.removeObserver(this._dismissPref, this._prefObserver); - } catch (e) { - // Ignore remove errors as observer might already be gone during shutdown. - } finally { - this._prefObserver = null; + for (const pref of this._dismissPrefs) { + try { + Services.prefs.removeObserver(pref, this._prefObserver); + } catch (_) { + // Ignore as the observer might already be removed during shutdown/teardown. + } } + this._prefObserver = null; } /** diff --git a/browser/components/asrouter/tests/browser/browser_asrouter_infobar.js b/browser/components/asrouter/tests/browser/browser_asrouter_infobar.js @@ -1439,3 +1439,46 @@ add_task(async function replace_global_with_global_and_record_impressions() { InfoBar._activeInfobar = null; InfoBar._universalInfobars = []; }); + +add_task(async function dismiss_on_any_pref_in_array_change() { + const PREF1 = "messaging-system-action.dismissOnChange.array.one"; + const PREF2 = "messaging-system-action.dismissOnChange.array.two"; + + const browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser; + const message = { + id: "TEST_DISMISS_ON_ANY_PREF_IN_ARRAY", + content: { + type: "global", + text: "array pref change", + dismissable: true, + buttons: [], + dismissOnPrefChange: [PREF1, PREF2], + }, + }; + + const dispatch = sinon.stub(); + const infobar = await InfoBar.showInfoBarMessage(browser, message, dispatch); + + // ignore initial impression + dispatch.resetHistory(); + + Services.prefs.setBoolPref(PREF2, true); + + await BrowserTestUtils.waitForCondition( + () => !infobar.notification, + "Infobar dismissed when pref in the array changes" + ); + + Assert.ok( + dispatch.calledWith( + sinon.match({ + type: "INFOBAR_TELEMETRY", + data: sinon.match.has("event", "DISMISSED"), + }) + ), + "DISMISSED telemetry sent on array pref change" + ); + + Services.prefs.clearUserPref(PREF1); + Services.prefs.clearUserPref(PREF2); +});