Loading browser/base/content/browser.js +3 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { AddonManager: "resource://gre/modules/AddonManager.jsm", AMTelemetry: "resource://gre/modules/AddonManager.jsm", NewTabPagePreloading: "resource:///modules/NewTabPagePreloading.jsm", BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm", BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm", BrowserUtils: "resource://gre/modules/BrowserUtils.jsm", BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm", Loading Loading @@ -4509,7 +4510,7 @@ const BrowserSearch = { */ recordSearchInTelemetry(engine, source, details = {}) { try { BrowserUsageTelemetry.recordSearch(gBrowser, engine, source, details); BrowserSearchTelemetry.recordSearch(gBrowser, engine, source, details); } catch (ex) { Cu.reportError(ex); } Loading @@ -4531,7 +4532,7 @@ const BrowserSearch = { recordOneoffSearchInTelemetry(engine, source, type) { try { const details = { type, isOneOff: true }; BrowserUsageTelemetry.recordSearch(gBrowser, engine, source, details); BrowserSearchTelemetry.recordSearch(gBrowser, engine, source, details); } catch (ex) { Cu.reportError(ex); } Loading browser/components/search/BrowserSearchTelemetry.jsm 0 → 100644 +365 −0 Original line number Diff line number Diff line /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; var EXPORTED_SYMBOLS = ["BrowserSearchTelemetry"]; const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); XPCOMUtils.defineLazyModuleGetters(this, { PartnerLinkAttribution: "resource:///modules/PartnerLinkAttribution.jsm", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", Services: "resource://gre/modules/Services.jsm", UrlbarUtils: "resource:///modules/UrlbarUtils.jsm", }); // A list of known search origins. const KNOWN_SEARCH_SOURCES = [ "abouthome", "contextmenu", "newtab", "searchbar", "system", "urlbar", "urlbar-searchmode", "webextension", ]; const KNOWN_ONEOFF_SOURCES = [ "oneoff-urlbar", "oneoff-searchbar", "unknown", // Edge case: this is the searchbar (see bug 1195733 comment 7). ]; /** * The handler class. TODO */ class BrowserSearchTelemetryHandler { /** * Determines if we should record a search for this browser instance. * Private Browsing mode is normally skipped. * * @param {tabbrowser} tabbrowser * The browser where the search was loaded. * @returns {boolean} * True if the search should be recorded, false otherwise. */ shouldRecordSearchCount(tabbrowser) { return ( !PrivateBrowsingUtils.isWindowPrivate(tabbrowser.ownerGlobal) || !Services.prefs.getBoolPref("browser.engagement.search_counts.pbm", false) ); } /** * The main entry point for recording search related Telemetry. This includes * search counts and engagement measurements. * * Telemetry records only search counts per engine and action origin, but * nothing pertaining to the search contents themselves. * * @param {tabbrowser} tabbrowser * The tabbrowser where the search was loaded. * @param {nsISearchEngine} engine * The engine handling the search. * @param {string} source * Where the search originated from. See KNOWN_SEARCH_SOURCES for allowed * values. * @param {object} [details] Options object. * @param {boolean} [details.isOneOff=false] * true if this event was generated by a one-off search. * @param {boolean} [details.isSuggestion=false] * true if this event was generated by a suggested search. * @param {boolean} [details.isFormHistory=false] * true if this event was generated by a form history result. * @param {string} [details.alias=null] * The search engine alias used in the search, if any. * @param {object} [details.type=null] * The object describing the event that triggered the search. * @throws if source is not in the known sources list. */ recordSearch(tabbrowser, engine, source, details = {}) { if (!this.shouldRecordSearchCount(tabbrowser)) { return; } const countIdPrefix = `${engine.telemetryId}.`; const countIdSource = countIdPrefix + source; let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); if (details.isOneOff) { if (!KNOWN_ONEOFF_SOURCES.includes(source)) { // Silently drop the error if this bogus call // came from 'urlbar' or 'searchbar'. They're // calling |recordSearch| twice from two different // code paths because they want to record the search // in SEARCH_COUNTS. if (["urlbar", "searchbar"].includes(source)) { histogram.add(countIdSource); PartnerLinkAttribution.makeSearchEngineRequest( engine, details.url ).catch(Cu.reportError); return; } throw new Error("Unknown source for one-off search: " + source); } } else { if (!KNOWN_SEARCH_SOURCES.includes(source)) { throw new Error("Unknown source for search: " + source); } if ( details.alias && engine.isAppProvided && engine.aliases.includes(details.alias) ) { // This is a keyword search using an AppProvided engine. // Record the source as "alias", not "urlbar". histogram.add(countIdPrefix + "alias"); } else { histogram.add(countIdSource); } } // Dispatch the search signal to other handlers. this._handleSearchAction(engine, source, details); } _recordSearch(engine, url, source, action = null) { // The one-off buttons are logged in two places, if we hit here with the // action as oneoff and no url, then we are hitting the attribution case // in `recordSearch` above. Really this needs re-architecturing so we // do not have two distinct calls to `recordSearch` for one-offs // (see bug 1662553). if (!(action == "oneoff" && !url)) { PartnerLinkAttribution.makeSearchEngineRequest(engine, url).catch( Cu.reportError ); } let scalarKey = action ? "search_" + action : "search"; Services.telemetry.keyedScalarAdd( "browser.engagement.navigation." + source, scalarKey, 1 ); Services.telemetry.recordEvent("navigation", "search", source, action, { engine: engine.telemetryId, }); } /** * Records entry into the Urlbar's search mode. * * Telemetry records only which search mode is entered and how it was entered. * It does not record anything pertaining to searches made within search mode. * @param {object} searchMode * A search mode object. See UrlbarInput.setSearchMode documentation for * details. */ recordSearchMode(searchMode) { // Search mode preview is not search mode. Recording it would just create // noise. if (searchMode.isPreview) { return; } let scalarKey; if (searchMode.engineName) { let engine = Services.search.getEngineByName(searchMode.engineName); let resultDomain = engine.getResultDomain(); // For built-in engines, sanitize the data in a few special cases to make // analysis easier. if (!engine.isAppProvided) { scalarKey = "other"; } else if (resultDomain.includes("amazon.")) { // Group all the localized Amazon sites together. scalarKey = "Amazon"; } else if (resultDomain.endsWith("wikipedia.org")) { // Group all the localized Wikipedia sites together. scalarKey = "Wikipedia"; } else { scalarKey = searchMode.engineName; } } else if (searchMode.source) { scalarKey = UrlbarUtils.getResultSourceName(searchMode.source) || "other"; } Services.telemetry.keyedScalarAdd( "urlbar.searchmode." + searchMode.entry, scalarKey, 1 ); } _handleSearchAction(engine, source, details) { switch (source) { case "urlbar": case "oneoff-urlbar": case "searchbar": case "oneoff-searchbar": case "unknown": // Edge case: this is the searchbar (see bug 1195733 comment 7). this._handleSearchAndUrlbar(engine, source, details); break; case "urlbar-searchmode": this._handleSearchAndUrlbar(engine, "urlbar_searchmode", details); break; case "abouthome": this._recordSearch(engine, details.url, "about_home", "enter"); break; case "newtab": this._recordSearch(engine, details.url, "about_newtab", "enter"); break; case "contextmenu": case "system": case "webextension": this._recordSearch(engine, details.url, source); break; } } /** * This function handles the "urlbar", "urlbar-oneoff", "searchbar" and * "searchbar-oneoff" sources. * * @param {msISearchEngine} engine * The engine handling the search. * @param {string} source * Where the search originated from. * @param {object} details * @see recordSearch */ _handleSearchAndUrlbar(engine, source, details) { // We want "urlbar" and "urlbar-oneoff" (and similar cases) to go in the same // scalar, but in a different key. // When using one-offs in the searchbar we get an "unknown" source. See bug // 1195733 comment 7 for the context. Fix-up the label here. const sourceName = source === "unknown" ? "searchbar" : source.replace("oneoff-", ""); const isOneOff = !!details.isOneOff; if (isOneOff) { // We will receive a signal from the "urlbar"/"searchbar" even when the // search came from "oneoff-urlbar". That's because both signals // are propagated from search.xml. Skip it if that's the case. // Moreover, we skip the "unknown" source that comes from the searchbar // when performing searches from the default search engine. See bug 1195733 // comment 7 for context. if (["urlbar", "searchbar", "unknown"].includes(source)) { return; } // If that's a legit one-off search signal, record it using the relative key. this._recordSearch(engine, details.url, sourceName, "oneoff"); return; } // The search was not a one-off. It was a search with the default search engine. if (details.isFormHistory) { // It came from a form history result. this._recordSearch(engine, details.url, sourceName, "formhistory"); return; } else if (details.isSuggestion) { // It came from a suggested search, so count it as such. this._recordSearch(engine, details.url, sourceName, "suggestion"); return; } else if (details.alias) { // This one came from a search that used an alias. this._recordSearch(engine, details.url, sourceName, "alias"); return; } // The search signal was generated by typing something and pressing enter. this._recordSearch(engine, details.url, sourceName, "enter"); } /** * Records the method by which the user selected a result from the urlbar. * * @param {Event} event * The event that triggered the selection. * @param {number} index * The index that the user chose in the popup, or -1 if there wasn't a * selection. * @param {string} userSelectionBehavior * How the user cycled through results before picking the current match. * Could be one of "tab", "arrow" or "none". */ recordUrlbarSelectedResultMethod( event, index, userSelectionBehavior = "none" ) { this._recordUrlOrSearchbarSelectedResultMethod( event, index, "FX_URLBAR_SELECTED_RESULT_METHOD", userSelectionBehavior ); } /** * Records the method by which the user selected a searchbar result. * * @param {Event} event * The event that triggered the selection. * @param {number} highlightedIndex * The index that the user chose in the popup, or -1 if there wasn't a * selection. */ recordSearchbarSelectedResultMethod(event, highlightedIndex) { this._recordUrlOrSearchbarSelectedResultMethod( event, highlightedIndex, "FX_SEARCHBAR_SELECTED_RESULT_METHOD", "none" ); } _recordUrlOrSearchbarSelectedResultMethod( event, highlightedIndex, histogramID, userSelectionBehavior ) { // If the contents of the histogram are changed then // `UrlbarTestUtils.SELECTED_RESULT_METHODS` should also be updated. let histogram = Services.telemetry.getHistogramById(histogramID); // command events are from the one-off context menu. Treat them as clicks. // Note that we don't care about MouseEvent subclasses here, since // those are not clicks. let isClick = event && (ChromeUtils.getClassName(event) == "MouseEvent" || event.type == "command"); let category; if (isClick) { category = "click"; } else if (highlightedIndex >= 0) { switch (userSelectionBehavior) { case "tab": category = "tabEnterSelection"; break; case "arrow": category = "arrowEnterSelection"; break; case "rightClick": // Selected by right mouse button. category = "rightClickEnter"; break; default: category = "enterSelection"; } } else { category = "enter"; } histogram.add(category); } } var BrowserSearchTelemetry = new BrowserSearchTelemetryHandler(); browser/components/search/SearchTelemetry.jsm +6 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ const { XPCOMUtils } = ChromeUtils.import( ); XPCOMUtils.defineLazyModuleGetters(this, { BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm", RemoteSettings: "resource://services-settings/remote-settings.js", SearchUtils: "resource://gre/modules/SearchUtils.jsm", Services: "resource://gre/modules/Services.jsm", Loading Loading @@ -191,6 +192,11 @@ class TelemetryHandler { * @param {string} url The url that was loaded in the browser. */ updateTrackingStatus(browser, url) { if ( !BrowserSearchTelemetry.shouldRecordSearchCount(browser.getTabBrowser()) ) { return; } let info = this._checkURLForSerpMatch(url); if (!info) { this.stopTrackingBrowser(browser); Loading browser/components/search/content/searchbar.js +1 −1 Original line number Diff line number Diff line Loading @@ -348,7 +348,7 @@ let selection = this.telemetrySearchDetails; let oneOffRecorded = false; BrowserUsageTelemetry.recordSearchbarSelectedResultMethod( BrowserSearchTelemetry.recordSearchbarSelectedResultMethod( aEvent, selection ? selection.index : -1 ); Loading browser/components/search/moz.build +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXTRA_JS_MODULES += [ "BrowserSearchTelemetry.jsm", "SearchOneOffs.jsm", "SearchTelemetry.jsm", "SearchUIUtils.jsm", Loading Loading
browser/base/content/browser.js +3 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { AddonManager: "resource://gre/modules/AddonManager.jsm", AMTelemetry: "resource://gre/modules/AddonManager.jsm", NewTabPagePreloading: "resource:///modules/NewTabPagePreloading.jsm", BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm", BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm", BrowserUtils: "resource://gre/modules/BrowserUtils.jsm", BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm", Loading Loading @@ -4509,7 +4510,7 @@ const BrowserSearch = { */ recordSearchInTelemetry(engine, source, details = {}) { try { BrowserUsageTelemetry.recordSearch(gBrowser, engine, source, details); BrowserSearchTelemetry.recordSearch(gBrowser, engine, source, details); } catch (ex) { Cu.reportError(ex); } Loading @@ -4531,7 +4532,7 @@ const BrowserSearch = { recordOneoffSearchInTelemetry(engine, source, type) { try { const details = { type, isOneOff: true }; BrowserUsageTelemetry.recordSearch(gBrowser, engine, source, details); BrowserSearchTelemetry.recordSearch(gBrowser, engine, source, details); } catch (ex) { Cu.reportError(ex); } Loading
browser/components/search/BrowserSearchTelemetry.jsm 0 → 100644 +365 −0 Original line number Diff line number Diff line /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; var EXPORTED_SYMBOLS = ["BrowserSearchTelemetry"]; const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); XPCOMUtils.defineLazyModuleGetters(this, { PartnerLinkAttribution: "resource:///modules/PartnerLinkAttribution.jsm", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", Services: "resource://gre/modules/Services.jsm", UrlbarUtils: "resource:///modules/UrlbarUtils.jsm", }); // A list of known search origins. const KNOWN_SEARCH_SOURCES = [ "abouthome", "contextmenu", "newtab", "searchbar", "system", "urlbar", "urlbar-searchmode", "webextension", ]; const KNOWN_ONEOFF_SOURCES = [ "oneoff-urlbar", "oneoff-searchbar", "unknown", // Edge case: this is the searchbar (see bug 1195733 comment 7). ]; /** * The handler class. TODO */ class BrowserSearchTelemetryHandler { /** * Determines if we should record a search for this browser instance. * Private Browsing mode is normally skipped. * * @param {tabbrowser} tabbrowser * The browser where the search was loaded. * @returns {boolean} * True if the search should be recorded, false otherwise. */ shouldRecordSearchCount(tabbrowser) { return ( !PrivateBrowsingUtils.isWindowPrivate(tabbrowser.ownerGlobal) || !Services.prefs.getBoolPref("browser.engagement.search_counts.pbm", false) ); } /** * The main entry point for recording search related Telemetry. This includes * search counts and engagement measurements. * * Telemetry records only search counts per engine and action origin, but * nothing pertaining to the search contents themselves. * * @param {tabbrowser} tabbrowser * The tabbrowser where the search was loaded. * @param {nsISearchEngine} engine * The engine handling the search. * @param {string} source * Where the search originated from. See KNOWN_SEARCH_SOURCES for allowed * values. * @param {object} [details] Options object. * @param {boolean} [details.isOneOff=false] * true if this event was generated by a one-off search. * @param {boolean} [details.isSuggestion=false] * true if this event was generated by a suggested search. * @param {boolean} [details.isFormHistory=false] * true if this event was generated by a form history result. * @param {string} [details.alias=null] * The search engine alias used in the search, if any. * @param {object} [details.type=null] * The object describing the event that triggered the search. * @throws if source is not in the known sources list. */ recordSearch(tabbrowser, engine, source, details = {}) { if (!this.shouldRecordSearchCount(tabbrowser)) { return; } const countIdPrefix = `${engine.telemetryId}.`; const countIdSource = countIdPrefix + source; let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); if (details.isOneOff) { if (!KNOWN_ONEOFF_SOURCES.includes(source)) { // Silently drop the error if this bogus call // came from 'urlbar' or 'searchbar'. They're // calling |recordSearch| twice from two different // code paths because they want to record the search // in SEARCH_COUNTS. if (["urlbar", "searchbar"].includes(source)) { histogram.add(countIdSource); PartnerLinkAttribution.makeSearchEngineRequest( engine, details.url ).catch(Cu.reportError); return; } throw new Error("Unknown source for one-off search: " + source); } } else { if (!KNOWN_SEARCH_SOURCES.includes(source)) { throw new Error("Unknown source for search: " + source); } if ( details.alias && engine.isAppProvided && engine.aliases.includes(details.alias) ) { // This is a keyword search using an AppProvided engine. // Record the source as "alias", not "urlbar". histogram.add(countIdPrefix + "alias"); } else { histogram.add(countIdSource); } } // Dispatch the search signal to other handlers. this._handleSearchAction(engine, source, details); } _recordSearch(engine, url, source, action = null) { // The one-off buttons are logged in two places, if we hit here with the // action as oneoff and no url, then we are hitting the attribution case // in `recordSearch` above. Really this needs re-architecturing so we // do not have two distinct calls to `recordSearch` for one-offs // (see bug 1662553). if (!(action == "oneoff" && !url)) { PartnerLinkAttribution.makeSearchEngineRequest(engine, url).catch( Cu.reportError ); } let scalarKey = action ? "search_" + action : "search"; Services.telemetry.keyedScalarAdd( "browser.engagement.navigation." + source, scalarKey, 1 ); Services.telemetry.recordEvent("navigation", "search", source, action, { engine: engine.telemetryId, }); } /** * Records entry into the Urlbar's search mode. * * Telemetry records only which search mode is entered and how it was entered. * It does not record anything pertaining to searches made within search mode. * @param {object} searchMode * A search mode object. See UrlbarInput.setSearchMode documentation for * details. */ recordSearchMode(searchMode) { // Search mode preview is not search mode. Recording it would just create // noise. if (searchMode.isPreview) { return; } let scalarKey; if (searchMode.engineName) { let engine = Services.search.getEngineByName(searchMode.engineName); let resultDomain = engine.getResultDomain(); // For built-in engines, sanitize the data in a few special cases to make // analysis easier. if (!engine.isAppProvided) { scalarKey = "other"; } else if (resultDomain.includes("amazon.")) { // Group all the localized Amazon sites together. scalarKey = "Amazon"; } else if (resultDomain.endsWith("wikipedia.org")) { // Group all the localized Wikipedia sites together. scalarKey = "Wikipedia"; } else { scalarKey = searchMode.engineName; } } else if (searchMode.source) { scalarKey = UrlbarUtils.getResultSourceName(searchMode.source) || "other"; } Services.telemetry.keyedScalarAdd( "urlbar.searchmode." + searchMode.entry, scalarKey, 1 ); } _handleSearchAction(engine, source, details) { switch (source) { case "urlbar": case "oneoff-urlbar": case "searchbar": case "oneoff-searchbar": case "unknown": // Edge case: this is the searchbar (see bug 1195733 comment 7). this._handleSearchAndUrlbar(engine, source, details); break; case "urlbar-searchmode": this._handleSearchAndUrlbar(engine, "urlbar_searchmode", details); break; case "abouthome": this._recordSearch(engine, details.url, "about_home", "enter"); break; case "newtab": this._recordSearch(engine, details.url, "about_newtab", "enter"); break; case "contextmenu": case "system": case "webextension": this._recordSearch(engine, details.url, source); break; } } /** * This function handles the "urlbar", "urlbar-oneoff", "searchbar" and * "searchbar-oneoff" sources. * * @param {msISearchEngine} engine * The engine handling the search. * @param {string} source * Where the search originated from. * @param {object} details * @see recordSearch */ _handleSearchAndUrlbar(engine, source, details) { // We want "urlbar" and "urlbar-oneoff" (and similar cases) to go in the same // scalar, but in a different key. // When using one-offs in the searchbar we get an "unknown" source. See bug // 1195733 comment 7 for the context. Fix-up the label here. const sourceName = source === "unknown" ? "searchbar" : source.replace("oneoff-", ""); const isOneOff = !!details.isOneOff; if (isOneOff) { // We will receive a signal from the "urlbar"/"searchbar" even when the // search came from "oneoff-urlbar". That's because both signals // are propagated from search.xml. Skip it if that's the case. // Moreover, we skip the "unknown" source that comes from the searchbar // when performing searches from the default search engine. See bug 1195733 // comment 7 for context. if (["urlbar", "searchbar", "unknown"].includes(source)) { return; } // If that's a legit one-off search signal, record it using the relative key. this._recordSearch(engine, details.url, sourceName, "oneoff"); return; } // The search was not a one-off. It was a search with the default search engine. if (details.isFormHistory) { // It came from a form history result. this._recordSearch(engine, details.url, sourceName, "formhistory"); return; } else if (details.isSuggestion) { // It came from a suggested search, so count it as such. this._recordSearch(engine, details.url, sourceName, "suggestion"); return; } else if (details.alias) { // This one came from a search that used an alias. this._recordSearch(engine, details.url, sourceName, "alias"); return; } // The search signal was generated by typing something and pressing enter. this._recordSearch(engine, details.url, sourceName, "enter"); } /** * Records the method by which the user selected a result from the urlbar. * * @param {Event} event * The event that triggered the selection. * @param {number} index * The index that the user chose in the popup, or -1 if there wasn't a * selection. * @param {string} userSelectionBehavior * How the user cycled through results before picking the current match. * Could be one of "tab", "arrow" or "none". */ recordUrlbarSelectedResultMethod( event, index, userSelectionBehavior = "none" ) { this._recordUrlOrSearchbarSelectedResultMethod( event, index, "FX_URLBAR_SELECTED_RESULT_METHOD", userSelectionBehavior ); } /** * Records the method by which the user selected a searchbar result. * * @param {Event} event * The event that triggered the selection. * @param {number} highlightedIndex * The index that the user chose in the popup, or -1 if there wasn't a * selection. */ recordSearchbarSelectedResultMethod(event, highlightedIndex) { this._recordUrlOrSearchbarSelectedResultMethod( event, highlightedIndex, "FX_SEARCHBAR_SELECTED_RESULT_METHOD", "none" ); } _recordUrlOrSearchbarSelectedResultMethod( event, highlightedIndex, histogramID, userSelectionBehavior ) { // If the contents of the histogram are changed then // `UrlbarTestUtils.SELECTED_RESULT_METHODS` should also be updated. let histogram = Services.telemetry.getHistogramById(histogramID); // command events are from the one-off context menu. Treat them as clicks. // Note that we don't care about MouseEvent subclasses here, since // those are not clicks. let isClick = event && (ChromeUtils.getClassName(event) == "MouseEvent" || event.type == "command"); let category; if (isClick) { category = "click"; } else if (highlightedIndex >= 0) { switch (userSelectionBehavior) { case "tab": category = "tabEnterSelection"; break; case "arrow": category = "arrowEnterSelection"; break; case "rightClick": // Selected by right mouse button. category = "rightClickEnter"; break; default: category = "enterSelection"; } } else { category = "enter"; } histogram.add(category); } } var BrowserSearchTelemetry = new BrowserSearchTelemetryHandler();
browser/components/search/SearchTelemetry.jsm +6 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ const { XPCOMUtils } = ChromeUtils.import( ); XPCOMUtils.defineLazyModuleGetters(this, { BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm", RemoteSettings: "resource://services-settings/remote-settings.js", SearchUtils: "resource://gre/modules/SearchUtils.jsm", Services: "resource://gre/modules/Services.jsm", Loading Loading @@ -191,6 +192,11 @@ class TelemetryHandler { * @param {string} url The url that was loaded in the browser. */ updateTrackingStatus(browser, url) { if ( !BrowserSearchTelemetry.shouldRecordSearchCount(browser.getTabBrowser()) ) { return; } let info = this._checkURLForSerpMatch(url); if (!info) { this.stopTrackingBrowser(browser); Loading
browser/components/search/content/searchbar.js +1 −1 Original line number Diff line number Diff line Loading @@ -348,7 +348,7 @@ let selection = this.telemetrySearchDetails; let oneOffRecorded = false; BrowserUsageTelemetry.recordSearchbarSelectedResultMethod( BrowserSearchTelemetry.recordSearchbarSelectedResultMethod( aEvent, selection ? selection.index : -1 ); Loading
browser/components/search/moz.build +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXTRA_JS_MODULES += [ "BrowserSearchTelemetry.jsm", "SearchOneOffs.jsm", "SearchTelemetry.jsm", "SearchUIUtils.jsm", Loading