commit 9ba705aa632e333700c3a0663e5ea7c07895826a
parent 98b6d6251634dbb404c11f130de2d173f780a4d1
Author: Stephen Thompson <sthompson@mozilla.com>
Date: Tue, 14 Oct 2025 21:00:36 +0000
Bug 1988855 Part 1 - telemetry for pref toggle "Open links from apps next to your active tab" r=mstriemer,tabbrowser-reviewers,Gijs
When a user toggles the "Open links from apps next to your active tab" checkbox in about:preferences, record that interaction and record the new value. This will help us understand whether people are using this feature, whether they are keeping it, etc.
Differential Revision: https://phabricator.services.mozilla.com/D266916
Diffstat:
4 files changed, 158 insertions(+), 6 deletions(-)
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
@@ -2985,7 +2985,12 @@ var gMainPane = {
const externalLinkOpenOverride = Preferences.get(
"browser.link.open_newwindow.override.external"
);
-
+ Glean.linkHandling.openNextToActiveTabSettingsEnabled.set(
+ inputElement.checked
+ );
+ Glean.linkHandling.openNextToActiveTabSettingsChange.record({
+ checked: inputElement.checked,
+ });
return inputElement.checked
? Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT
: externalLinkOpenOverride.defaultValue;
diff --git a/browser/components/preferences/tests/browser_tabs_open_external_next_to_active_tab.js b/browser/components/preferences/tests/browser_tabs_open_external_next_to_active_tab.js
@@ -7,14 +7,86 @@ const PREF_NAME = "browser.link.open_newwindow.override.external";
const PREF_VALUE_FEATURE_OFF = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_BACKGROUND;
const PREF_VALUE_FEATURE_ON = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT;
+let resetTelemetry = async () => {
+ await Services.fog.testFlushAllChildren();
+ Services.fog.testResetFOG();
+};
+
+registerCleanupFunction(async () => {
+ await resetTelemetry();
+});
+
+/**
+ * @param {boolean} shouldBeEnabled
+ */
+async function assertOpenNextToActiveTabSettingsEnabled(shouldBeEnabled) {
+ await TestUtils.waitForCondition(
+ () =>
+ Glean.linkHandling.openNextToActiveTabSettingsEnabled.testGetValue() ===
+ shouldBeEnabled,
+ "wait for metric to be recorded"
+ );
+ Assert.equal(
+ Glean.linkHandling.openNextToActiveTabSettingsEnabled.testGetValue(),
+ shouldBeEnabled,
+ `metric should have recorded that the pref is ${shouldBeEnabled ? "on" : "off"}`
+ );
+}
+
+/**
+ * @param {number} nthEvent
+ * @param {boolean} shouldBeChecked
+ */
+async function assertOpenNextToActiveTabSettingsChange(
+ nthEvent,
+ shouldBeChecked
+) {
+ await TestUtils.waitForCondition(
+ () =>
+ Glean.linkHandling.openNextToActiveTabSettingsChange.testGetValue()
+ ?.length == nthEvent,
+ "wait for event to be recorded"
+ );
+ let settingsChangeEvents =
+ Glean.linkHandling.openNextToActiveTabSettingsChange.testGetValue();
+ Assert.ok(settingsChangeEvents, "an event should have been recorded");
+ Assert.equal(
+ settingsChangeEvents.length,
+ nthEvent,
+ `${nthEvent} event(s) should have been recorded so far`
+ );
+ Assert.equal(
+ settingsChangeEvents[nthEvent - 1].extra.checked,
+ shouldBeChecked.toString(),
+ `event #${nthEvent} should record that the checkbox was ${shouldBeChecked ? "checked" : "not checked"}`
+ );
+}
+
+/**
+ * @param {number} expectedCounterValue
+ */
+async function assertBrowserUiInteraction(expectedCounterValue) {
+ await TestUtils.waitForCondition(
+ () =>
+ Glean.browserUiInteraction.preferencesPaneGeneral?.openAppLinksNextToActiveTab?.testGetValue() ==
+ expectedCounterValue,
+ "wait for metric to be recorded"
+ );
+ Assert.equal(
+ Glean.browserUiInteraction.preferencesPaneGeneral.openAppLinksNextToActiveTab.testGetValue(),
+ expectedCounterValue,
+ "click on the pref checkbox should have been counted"
+ );
+}
+
add_task(async function test_open_external_link_next_to_active_tab_pref() {
await SpecialPowers.pushPrefEnv({
set: [[PREF_NAME, PREF_VALUE_FEATURE_OFF]],
});
-
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
leaveOpen: true,
});
+ await resetTelemetry();
const doc = gBrowser.contentDocument;
const checkbox = doc.getElementById("openAppLinksNextToActiveTab");
@@ -23,12 +95,10 @@ add_task(async function test_open_external_link_next_to_active_tab_pref() {
Assert.ok(checkbox, "pref should have a checkbox");
Assert.ok(
!checkbox.checked,
- "pref checkbox should not be checked by default"
+ "pref checkbox should not be checked when the feature is off"
);
- info(
- "validate checking and unchecking the pref checkbox under default conditions"
- );
+ info("validate checking and unchecking the pref checkbox");
let becameChecked = BrowserTestUtils.waitForAttribute("checked", checkbox);
checkbox.click();
await becameChecked;
@@ -38,6 +108,9 @@ add_task(async function test_open_external_link_next_to_active_tab_pref() {
PREF_VALUE_FEATURE_ON,
"pref should be set to open external links after the active tab"
);
+ await assertOpenNextToActiveTabSettingsEnabled(true);
+ await assertOpenNextToActiveTabSettingsChange(1, true);
+ await assertBrowserUiInteraction(1);
let becameUnchecked = BrowserTestUtils.waitForAttributeRemoval(
"checked",
@@ -50,6 +123,9 @@ add_task(async function test_open_external_link_next_to_active_tab_pref() {
!Services.prefs.prefHasUserValue(PREF_NAME),
"pref should have been reverted to its default value"
);
+ await assertOpenNextToActiveTabSettingsEnabled(false);
+ await assertOpenNextToActiveTabSettingsChange(2, false);
+ await assertBrowserUiInteraction(2);
await SpecialPowers.popPrefEnv();
BrowserTestUtils.removeTab(gBrowser.selectedTab, { animate: false });
diff --git a/browser/components/tabbrowser/metrics.yaml b/browser/components/tabbrowser/metrics.yaml
@@ -770,3 +770,43 @@ browser.tabclose:
- mconley@mozilla.com
expires: never
telemetry_mirror: FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS
+
+link.handling:
+ open_next_to_active_tab_settings_enabled:
+ type: boolean
+ lifetime: application
+ description: >
+ Records if the user has the "Open links from apps next to your active tab"
+ feature enabled.
+ notification_emails:
+ - sthompson@mozilla.com
+ bugs:
+ - https://bugzil.la/1988855
+ data_reviews:
+ - https://bugzil.la/1988855
+ data_sensitivity:
+ - interaction
+ expires: never
+ no_lint:
+ - COMMON_PREFIX
+ open_next_to_active_tab_settings_change:
+ type: event
+ description: >
+ This is recorded when the "Open links from apps next to your active tab"
+ checkbox in the General > Tabs section of about:preferences is toggled.
+ bugs:
+ - https://bugzil.la/1988855
+ data_reviews:
+ - https://bugzil.la/1988855
+ data_sensitivity:
+ - interaction
+ notification_emails:
+ - sthompson@mozilla.com
+ expires: never
+ extra_keys:
+ checked:
+ description: >
+ Whether the checkbox was toggled on or off.
+ type: boolean
+ no_lint:
+ - COMMON_PREFIX
diff --git a/browser/modules/BrowserUsageTelemetry.sys.mjs b/browser/modules/BrowserUsageTelemetry.sys.mjs
@@ -522,8 +522,10 @@ export let BrowserUsageTelemetry = {
"media.videocontrols.picture-in-picture.enable-when-switching-tabs.enabled",
this
);
+ Services.prefs.addObserver("idle-daily", this);
this._recordUITelemetry();
+ this._recordInitialPrefValues();
this.recordPinnedTabsCount();
this._onTabsOpenedTask = new lazy.DeferredTask(
@@ -637,6 +639,10 @@ export let BrowserUsageTelemetry = {
Glean.pictureinpictureSettings.enableAutotriggerSettings.record();
}
break;
+
+ case "idle-daily":
+ this._recordInitialPrefValues();
+ break;
}
break;
}
@@ -1212,6 +1218,31 @@ export let BrowserUsageTelemetry = {
},
/**
+ * Records the startup values of prefs that govern important browser behavior
+ * options.
+ */
+ _recordInitialPrefValues() {
+ this._recordOpenNextToActiveTabSettingValue();
+ },
+
+ /**
+ * @param {number} prefValue
+ * pref `browser.link.open_newwindow.override.external`
+ */
+ _isOpenNextToActiveTabSettingEnabled(prefValue) {
+ return prefValue == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT;
+ },
+
+ _recordOpenNextToActiveTabSettingValue() {
+ const value = Services.prefs.getIntPref(
+ "browser.link.open_newwindow.override.external"
+ );
+ Glean.linkHandling.openNextToActiveTabSettingsEnabled.set(
+ this._isOpenNextToActiveTabSettingEnabled(value)
+ );
+ },
+
+ /**
* Adds listeners to a single chrome window.
* @param {Window} win
*/