diff --git a/browser/modules/BrowserUsageTelemetry.jsm b/browser/modules/BrowserUsageTelemetry.jsm index e5a000a04046..8db49691dcb5 100644 --- a/browser/modules/BrowserUsageTelemetry.jsm +++ b/browser/modules/BrowserUsageTelemetry.jsm @@ -40,6 +40,8 @@ const AUTOCOMPLETE_ENTER_TEXT_TOPIC = "autocomplete-did-enter-text"; const MAX_TAB_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_tab_count"; const MAX_WINDOW_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_window_count"; const TAB_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.tab_open_event_count"; +const MAX_TAB_PINNED_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_tab_pinned_count"; +const TAB_PINNED_EVENT_COUNT_SCALAR_NAME = "browser.engagement.tab_pinned_event_count"; const WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.window_open_event_count"; const UNIQUE_DOMAINS_COUNT_SCALAR_NAME = "browser.engagement.unique_domains_count"; const TOTAL_URI_COUNT_SCALAR_NAME = "browser.engagement.total_uri_count"; @@ -114,6 +116,16 @@ function getTabCount() { return getOpenTabsAndWinsCounts().tabCount; } +function getPinnedTabsCount() { + let pinnedTabs = 0; + + for (let win of Services.wm.getEnumerator("navigator:browser")) { + pinnedTabs += [...win.ownerGlobal.gBrowser.tabs].filter(t => t.pinned).length; + } + + return pinnedTabs; +} + function getSearchEngineId(engine) { if (engine) { if (engine.identifier) { @@ -424,6 +436,9 @@ let BrowserUsageTelemetry = { case "TabOpen": this._onTabOpen(); break; + case "TabPinned": + this._onTabPinned(); + break; case "unload": this._unregisterWindow(event.target); break; @@ -704,6 +719,7 @@ let BrowserUsageTelemetry = { _registerWindow(win) { win.addEventListener("unload", this); win.addEventListener("TabOpen", this, true); + win.addEventListener("TabPinned", this, true); win.gBrowser.tabContainer.addEventListener(TAB_RESTORING_TOPIC, this); win.gBrowser.addTabsProgressListener(URICountListener); @@ -715,6 +731,7 @@ let BrowserUsageTelemetry = { _unregisterWindow(win) { win.removeEventListener("unload", this); win.removeEventListener("TabOpen", this, true); + win.removeEventListener("TabPinned", this, true); win.defaultView.gBrowser.tabContainer.removeEventListener(TAB_RESTORING_TOPIC, this); win.defaultView.gBrowser.removeTabsProgressListener(URICountListener); @@ -735,6 +752,14 @@ let BrowserUsageTelemetry = { this._recordTabCount(tabCount); }, + _onTabPinned(target) { + const pinnedTabs = getPinnedTabsCount(); + + // Update the "tab pinned" count and its maximum. + Services.telemetry.scalarAdd(TAB_PINNED_EVENT_COUNT_SCALAR_NAME, 1); + Services.telemetry.scalarSetMaximum(MAX_TAB_PINNED_COUNT_SCALAR_NAME, pinnedTabs); + }, + /** * Tracks the window count and registers the listeners for the tab count. * @param{Object} win The window object. diff --git a/browser/modules/test/browser/browser_UsageTelemetry.js b/browser/modules/test/browser/browser_UsageTelemetry.js index abac63265ecc..1f208c711ef4 100644 --- a/browser/modules/test/browser/browser_UsageTelemetry.js +++ b/browser/modules/test/browser/browser_UsageTelemetry.js @@ -3,6 +3,8 @@ const MAX_CONCURRENT_TABS = "browser.engagement.max_concurrent_tab_count"; const TAB_EVENT_COUNT = "browser.engagement.tab_open_event_count"; const MAX_CONCURRENT_WINDOWS = "browser.engagement.max_concurrent_window_count"; +const MAX_TAB_PINNED = "browser.engagement.max_concurrent_tab_pinned_count"; +const TAB_PINNED_EVENT = "browser.engagement.tab_pinned_event_count"; const WINDOW_OPEN_COUNT = "browser.engagement.window_open_event_count"; const TOTAL_URI_COUNT = "browser.engagement.total_uri_count"; const UNIQUE_DOMAINS_COUNT = "browser.engagement.unique_domains_count"; @@ -27,6 +29,10 @@ let checkScalars = (countsObject) => { "The maximum tab count must match the expected value."); TelemetryTestUtils.assertScalar(scalars, TAB_EVENT_COUNT, countsObject.tabOpenCount, "The number of open tab event count must match the expected value."); + TelemetryTestUtils.assertScalar(scalars, MAX_TAB_PINNED, countsObject.maxTabsPinned, + "The maximum tabs pinned count must match the expected value."); + TelemetryTestUtils.assertScalar(scalars, TAB_PINNED_EVENT, countsObject.tabPinnedCount, + "The number of tab pinned event count must match the expected value."); TelemetryTestUtils.assertScalar(scalars, MAX_CONCURRENT_WINDOWS, countsObject.maxWindows, "The maximum window count must match the expected value."); TelemetryTestUtils.assertScalar(scalars, WINDOW_OPEN_COUNT, countsObject.windowsOpenCount, @@ -48,25 +54,43 @@ add_task(async function test_tabsAndWindows() { let expectedWinOpenCount = 0; let expectedMaxTabs = 0; let expectedMaxWins = 0; + let expectedMaxTabsPinned = 0; + let expectedTabPinned = 0; // Add a new tab and check that the count is right. openedTabs.push(await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank")); + + gBrowser.pinTab(openedTabs[0]); + gBrowser.unpinTab(openedTabs[0]); + expectedTabOpenCount = 1; expectedMaxTabs = 2; + expectedMaxTabsPinned = 1; + expectedTabPinned += 1; // This, and all the checks below, also check that initial pages (about:newtab, about:blank, ..) // are not counted by the total_uri_count and the unfiltered_uri_count probes. checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins, windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0, - totalUnfilteredURIs: 0}); + totalUnfilteredURIs: 0, maxTabsPinned: expectedMaxTabsPinned, + tabPinnedCount: expectedTabPinned}); // Add two new tabs in the same window. openedTabs.push(await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank")); openedTabs.push(await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank")); + + gBrowser.pinTab(openedTabs[1]); + gBrowser.pinTab(openedTabs[2]); + gBrowser.unpinTab(openedTabs[2]); + gBrowser.unpinTab(openedTabs[1]); + expectedTabOpenCount += 2; expectedMaxTabs += 2; + expectedMaxTabsPinned = 2; + expectedTabPinned += 2; checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins, windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0, - totalUnfilteredURIs: 0}); + totalUnfilteredURIs: 0, maxTabsPinned: expectedMaxTabsPinned, + tabPinnedCount: expectedTabPinned}); // Add a new window and then some tabs in it. An empty new windows counts as a tab. let win = await BrowserTestUtils.openNewBrowserWindow(); @@ -83,7 +107,8 @@ add_task(async function test_tabsAndWindows() { BrowserTestUtils.removeTab(openedTabs.pop()); checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins, windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0, - totalUnfilteredURIs: 0}); + totalUnfilteredURIs: 0, maxTabsPinned: expectedMaxTabsPinned, + tabPinnedCount: expectedTabPinned}); // Remove all the extra windows and tabs. for (let tab of openedTabs) { @@ -94,7 +119,8 @@ add_task(async function test_tabsAndWindows() { // Make sure all the scalars still have the expected values. checkScalars({maxTabs: expectedMaxTabs, tabOpenCount: expectedTabOpenCount, maxWindows: expectedMaxWins, windowsOpenCount: expectedWinOpenCount, totalURIs: 0, domainCount: 0, - totalUnfilteredURIs: 0}); + totalUnfilteredURIs: 0, maxTabsPinned: expectedMaxTabsPinned, + tabPinnedCount: expectedTabPinned}); }); add_task(async function test_subsessionSplit() { @@ -112,7 +138,8 @@ add_task(async function test_subsessionSplit() { // (about:mozilla and www.example.com, but no about:blank) and 1 URI totalURIs // (only www.example.com). checkScalars({maxTabs: 5, tabOpenCount: 4, maxWindows: 2, windowsOpenCount: 1, - totalURIs: 1, domainCount: 1, totalUnfilteredURIs: 2}); + totalURIs: 1, domainCount: 1, totalUnfilteredURIs: 2, maxTabsPinned: 0, + tabPinnedCount: 0}); // Remove a tab. BrowserTestUtils.removeTab(openedTabs.pop()); @@ -126,7 +153,8 @@ add_task(async function test_subsessionSplit() { // and have the correct value. No tabs, windows or URIs were opened so other scalars // must not be reported. checkScalars({maxTabs: 4, tabOpenCount: 0, maxWindows: 2, windowsOpenCount: 0, - totalURIs: 0, domainCount: 0, totalUnfilteredURIs: 0}); + totalURIs: 0, domainCount: 0, totalUnfilteredURIs: 0, maxTabsPinned: 0, + tabPinnedCount: 0}); // Remove all the extra windows and tabs. for (let tab of openedTabs) { diff --git a/toolkit/components/telemetry/Scalars.yaml b/toolkit/components/telemetry/Scalars.yaml index d48b4ead9f64..a0fbba029a7d 100644 --- a/toolkit/components/telemetry/Scalars.yaml +++ b/toolkit/components/telemetry/Scalars.yaml @@ -95,6 +95,36 @@ browser.engagement: record_in_processes: - 'main' + max_concurrent_tab_pinned_count: + bug_numbers: + - 1505535 + description: > + The count of maximum number of pinned tabs open during a subsession. This + includes private windows and the ones opened when starting the browser. + expires: never + kind: uint + notification_emails: + - bmiroglio@mozilla.com + - aoprea@mozilla.com + release_channel_collection: opt-out + record_in_processes: + - 'main' + + tab_pinned_event_count: + bug_numbers: + - 1505535 + description: > + The count of tab pinned events per subsession, across all windows, after the + session has been restored. This includes tab pinned events from private windows. + expires: never + kind: uint + notification_emails: + - bmiroglio@mozilla.com + - aoprea@mozilla.com + release_channel_collection: opt-out + record_in_processes: + - 'main' + total_uri_count: bug_numbers: - 1271313