Bug 1620358: Gather telemetry on toolbar state. r=Gijs,zombie

Differential Revision: https://phabricator.services.mozilla.com/D78393
This commit is contained in:
Dave Townsend 2020-06-16 21:06:15 +00:00
Родитель 778747ede9
Коммит e07f989e6c
21 изменённых файлов: 2237 добавлений и 21 удалений

Просмотреть файл

@ -144,7 +144,7 @@
<menupopup id="menu_viewPopup"
onpopupshowing="updateCharacterEncodingMenuState();">
<menu id="viewToolbarsMenu" data-l10n-id="menu-view-toolbars-menu">
<menupopup onpopupshowing="onViewToolbarsPopupShowing(event);">
<menupopup id="view-menu-popup" onpopupshowing="onViewToolbarsPopupShowing(event);">
<menuseparator/>
<menuitem id="menu_customizeToolbars"
command="cmd_CustomizeToolbars" data-l10n-id="menu-view-customize-toolbar"/>

Просмотреть файл

@ -956,6 +956,11 @@ var BrowserPageActions = {
this._contextAction = null;
action.pinnedToUrlbar = !action.pinnedToUrlbar;
BrowserUsageTelemetry.recordWidgetChange(
action.id,
action.pinnedToUrlbar ? "page-action-buttons" : null,
"pageaction-context"
);
},
/**

Просмотреть файл

@ -1431,11 +1431,16 @@ var BookmarkingUI = {
);
},
toggleBookmarksToolbar() {
toggleBookmarksToolbar(reason) {
CustomizableUI.setToolbarVisibility(
"PersonalToolbar",
document.getElementById("PersonalToolbar").collapsed
);
BrowserUsageTelemetry.recordToolbarVisibility(
"PersonalToolbar",
document.getElementById("PersonalToolbar").collapsed,
reason
);
},
attachPlacesView(event, node) {
@ -1924,9 +1929,19 @@ var BookmarkingUI = {
}
CustomizableUI.addWidgetToArea(this.BOOKMARK_BUTTON_ID, area, pos);
BrowserUsageTelemetry.recordWidgetChange(
this.BOOKMARK_BUTTON_ID,
area,
"bookmark-tools"
);
} else {
// Move it back to the palette.
CustomizableUI.removeWidgetFromArea(this.BOOKMARK_BUTTON_ID);
BrowserUsageTelemetry.recordWidgetChange(
this.BOOKMARK_BUTTON_ID,
null,
"bookmark-tools"
);
}
triggerNode.setAttribute("checked", !placement);
updateToggleControlLabel(triggerNode);

Просмотреть файл

@ -6403,9 +6403,11 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) {
function onViewToolbarCommand(aEvent) {
let node = aEvent.originalTarget;
let menuId = node.parentNode.id;
let toolbarId = node.getAttribute("toolbarId");
let isVisible = node.getAttribute("checked") == "true";
CustomizableUI.setToolbarVisibility(toolbarId, isVisible);
BrowserUsageTelemetry.recordToolbarVisibility(toolbarId, isVisible, menuId);
updateToggleControlLabel(node);
}

Просмотреть файл

@ -419,7 +419,7 @@
contexttype="toolbaritem"
class="customize-context-reportExtension"/>
<menuseparator/>
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode, 'toolbar-context-menu')"
data-lazy-l10n-id="toolbar-context-menu-pin-to-overflow-menu"
contexttype="toolbaritem"
class="customize-context-moveToPanel"/>
@ -428,7 +428,7 @@
type="checkbox"
data-lazy-l10n-id="toolbar-context-menu-auto-hide-downloads-button"
contexttype="toolbaritem"/>
<menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode)"
<menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode, 'toolbar-context-menu')"
data-lazy-l10n-id="toolbar-context-menu-remove-from-toolbar"
contexttype="toolbaritem"
class="customize-context-removeFromToolbar"/>
@ -1341,7 +1341,7 @@
class="menuitem-iconic subviewbutton"
label-show="&viewBookmarksToolbar.label;"
label-hide="&hideBookmarksToolbar.label;"
oncommand="BookmarkingUI.toggleBookmarksToolbar();"/>
oncommand="BookmarkingUI.toggleBookmarksToolbar('bookmarks-widget');"/>
<menuseparator/>
<!-- Bookmarks toolbar items -->
</menupopup>

Просмотреть файл

@ -21,6 +21,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PanelMultiView: "resource:///modules/PanelMultiView.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm",
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
});
XPCOMUtils.defineLazyGetter(this, "gWidgetsBundle", function() {
@ -4388,6 +4389,9 @@ var CustomizableUI = {
if (!item.hasAttribute("onclick")) {
subviewItem.addEventListener("click", event => {
let newEvent = new doc.defaultView.MouseEvent(event.type, event);
// Telemetry should only pay attention to the original event.
BrowserUsageTelemetry.ignoreEvent(newEvent);
item.dispatchEvent(newEvent);
});
}
@ -4408,6 +4412,9 @@ var CustomizableUI = {
event.sourceEvent,
0
);
// Telemetry should only pay attention to the original event.
BrowserUsageTelemetry.ignoreEvent(newEvent);
item.dispatchEvent(newEvent);
});
}

Просмотреть файл

@ -54,6 +54,11 @@ ChromeUtils.defineModuleGetter(
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUsageTelemetry",
"resource:///modules/BrowserUsageTelemetry.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"SessionStore",
@ -668,7 +673,7 @@ CustomizeMode.prototype = {
});
},
async addToToolbar(aNode) {
async addToToolbar(aNode, aReason) {
aNode = this._getCustomizableChildForNode(aNode);
if (aNode.localName == "toolbarpaletteitem" && aNode.firstElementChild) {
aNode = aNode.firstElementChild;
@ -690,6 +695,10 @@ CustomizeMode.prototype = {
}
CustomizableUI.addWidgetToArea(widgetToAdd, CustomizableUI.AREA_NAVBAR);
BrowserUsageTelemetry.recordWidgetChange(
widgetToAdd,
CustomizableUI.AREA_NAVBAR
);
if (!this._customizing) {
CustomizableUI.dispatchToolboxEvent("customizationchange");
}
@ -707,7 +716,7 @@ CustomizeMode.prototype = {
}
},
async addToPanel(aNode) {
async addToPanel(aNode, aReason) {
aNode = this._getCustomizableChildForNode(aNode);
if (aNode.localName == "toolbarpaletteitem" && aNode.firstElementChild) {
aNode = aNode.firstElementChild;
@ -720,6 +729,7 @@ CustomizeMode.prototype = {
let panel = CustomizableUI.AREA_FIXED_OVERFLOW_PANEL;
CustomizableUI.addWidgetToArea(aNode.id, panel);
BrowserUsageTelemetry.recordWidgetChange(aNode.id, panel, aReason);
if (!this._customizing) {
CustomizableUI.dispatchToolboxEvent("customizationchange");
}
@ -754,7 +764,7 @@ CustomizeMode.prototype = {
}
},
async removeFromArea(aNode) {
async removeFromArea(aNode, aReason) {
aNode = this._getCustomizableChildForNode(aNode);
if (aNode.localName == "toolbarpaletteitem" && aNode.firstElementChild) {
aNode = aNode.firstElementChild;
@ -766,6 +776,7 @@ CustomizeMode.prototype = {
}
CustomizableUI.removeWidgetFromArea(aNode.id);
BrowserUsageTelemetry.recordWidgetChange(aNode.id, null, aReason);
if (!this._customizing) {
CustomizableUI.dispatchToolboxEvent("customizationchange");
}
@ -2089,7 +2100,8 @@ CustomizeMode.prototype = {
return;
}
CustomizableUI.removeWidgetFromArea(aDraggedItemId);
CustomizableUI.removeWidgetFromArea(aDraggedItemId, "drag");
BrowserUsageTelemetry.recordWidgetChange(aDraggedItemId, null, "drag");
// Special widgets are removed outright, we can return here:
if (CustomizableUI.isSpecialWidget(aDraggedItemId)) {
return;
@ -2148,6 +2160,11 @@ CustomizeMode.prototype = {
// widget to the end of the area.
if (aTargetNode == areaCustomizationTarget) {
CustomizableUI.addWidgetToArea(aDraggedItemId, aTargetArea.id);
BrowserUsageTelemetry.recordWidgetChange(
aDraggedItemId,
aTargetArea.id,
"drag"
);
this._onDragEnd(aEvent);
return;
}
@ -2196,8 +2213,18 @@ CustomizeMode.prototype = {
// that the widget is moving within a customizable area.
if (aTargetArea == aOriginArea) {
CustomizableUI.moveWidgetWithinArea(aDraggedItemId, position);
BrowserUsageTelemetry.recordWidgetChange(
aDraggedItemId,
aTargetArea.id,
"drag"
);
} else {
CustomizableUI.addWidgetToArea(aDraggedItemId, aTargetArea.id, position);
BrowserUsageTelemetry.recordWidgetChange(
aDraggedItemId,
aTargetArea.id,
"drag"
);
}
this._onDragEnd(aEvent);
@ -2639,6 +2666,11 @@ CustomizeMode.prototype = {
"nav-bar",
insertionPoint
);
BrowserUsageTelemetry.recordWidgetChange(
"downloads-button",
"nav-bar",
"move-downloads"
);
}
},

Просмотреть файл

@ -21,6 +21,11 @@ ChromeUtils.defineModuleGetter(
"CustomizableUI",
"resource:///modules/CustomizableUI.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUsageTelemetry",
"resource:///modules/BrowserUsageTelemetry.jsm"
);
const WIDGET_ID = "search-container";
const PREF_NAME = "browser.search.widget.inNavBar";
@ -85,8 +90,14 @@ const SearchWidgetTracker = {
CustomizableUI.AREA_NAVBAR,
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
);
BrowserUsageTelemetry.recordWidgetChange(
WIDGET_ID,
CustomizableUI.AREA_NAVBAR,
"searchpref"
);
} else {
CustomizableUI.removeWidgetFromArea(WIDGET_ID);
BrowserUsageTelemetry.recordWidgetChange(WIDGET_ID, null, "searchpref");
}
},

Просмотреть файл

@ -43,18 +43,18 @@
contexttype="toolbaritem"
class="customize-context-reportExtension"/>
<menuseparator/>
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode, 'panelitem-context')"
id="customizationPanelItemContextMenuPin"
data-lazy-l10n-id="toolbar-context-menu-pin-to-overflow-menu"
closemenu="single"
class="customize-context-moveToPanel"/>
<menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)"
<menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode, 'panelitem-context')"
id="customizationPanelItemContextMenuUnpin"
closemenu="single"
class="customize-context-moveToToolbar"
accesskey="&customizeMenu.unpinFromOverflowMenu.accesskey;"
label="&customizeMenu.unpinFromOverflowMenu.label;"/>
<menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode)"
<menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode, 'panelitem-context')"
closemenu="single"
class="customize-context-removeFromPanel"
data-lazy-l10n-id="toolbar-context-menu-remove-from-toolbar"/>
@ -179,11 +179,11 @@
<html:template id="customModeWrapper">
<menupopup id="customizationPaletteItemContextMenu"
onpopupshowing="gCustomizeMode.onPaletteContextMenuShowing(event)">
<menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)"
<menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode, 'palette-context')"
class="customize-context-addToToolbar"
accesskey="&customizeMenu.addToToolbar.accesskey;"
label="&customizeMenu.addToToolbar.label;"/>
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode, 'palette-context')"
class="customize-context-addToPanel"
accesskey="&customizeMenu.addToOverflowMenu.accesskey;"
label="&customizeMenu.addToOverflowMenu.label;"/>
@ -222,7 +222,7 @@
descriptionheightworkaround="true">
<vbox class="panel-subview-body">
<vbox id="appMenu-addon-banners"/>
<toolbarbutton class="panel-banner-item"
<toolbarbutton id="appMenu-update-banner" class="panel-banner-item"
label-update-available="&updateAvailable.panelUI.label;"
label-update-manual="&updateManual.panelUI.label;"
label-update-unsupported="&updateUnsupported.panelUI.label;"
@ -530,6 +530,7 @@
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label>
<hbox pack="center">
<toolbarbutton class="PanelUI-remotetabs-button"
id="PanelUI-remotetabs-tabsdisabledpane-button"
label="&appMenuRemoteTabs.opensyncprefs.label;"
oncommand="gSync.openPrefs('synced-tabs');"/>
</hbox>
@ -565,6 +566,7 @@
<image class="fxaSyncIllustration"/>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.welcome.label;</label>
<toolbarbutton class="PanelUI-remotetabs-button"
id="PanelUI-remotetabs-setupsync-button"
label="&appMenuRemoteTabs.signintosync.label;"
oncommand="gSync.openPrefs('synced-tabs');"/>
</vbox>
@ -577,6 +579,7 @@
<image class="fxaSyncIllustration"/>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.welcome.label;</label>
<toolbarbutton class="PanelUI-remotetabs-button"
id="PanelUI-remotetabs-syncdisabled-button"
label="&appMenuRemoteTabs.turnonsync.label;"
oncommand="gSync.openPrefs('synced-tabs');"/>
</vbox>
@ -589,6 +592,7 @@
<image class="fxaSyncIllustrationIssue"/>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.welcome.label;</label>
<toolbarbutton class="PanelUI-remotetabs-button"
id="PanelUI-remotetabs-reauthsync-button"
label="&appMenuRemoteTabs.signintosync.label;"
oncommand="gSync.openPrefs('synced-tabs');"/>
</vbox>
@ -601,6 +605,7 @@
<image class="fxaSyncIllustrationIssue"/>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.unverified.label;</label>
<toolbarbutton class="PanelUI-remotetabs-button"
id="PanelUI-remotetabs-unverified-button"
label="&appMenuRemoteTabs.opensyncprefs.label;"
oncommand="gSync.openPrefs('synced-tabs');"/>
</vbox>
@ -699,7 +704,7 @@
<!-- The rest of the values get dynamically inserted. The "presetsbuilt"
attribute will get updated to "true" once the presets have been
built. -->
<menuitem label="Custom" value="custom"/>
<menuitem id="PanelUI-profiler-presets-custom" label="Custom" value="custom"/>
</menupopup>
</menulist>
<!-- The following description gets inserted dynamically. -->
@ -963,7 +968,7 @@
class="subviewbutton subviewbutton-iconic"
label-show="&viewBookmarksToolbar.label;"
label-hide="&hideBookmarksToolbar.label;"
oncommand="BookmarkingUI.toggleBookmarksToolbar();"/>
oncommand="BookmarkingUI.toggleBookmarksToolbar('bookmark-tools');"/>
</vbox>
</panelview>

Просмотреть файл

@ -11,6 +11,7 @@
"url": "chrome://browser/content/parent/ext-browserAction.js",
"schema": "chrome://extensions/content/schemas/browser_action.json",
"scopes": ["addon_parent"],
"events": ["update", "uninstall", "disable"],
"manifest": ["browser_action"],
"paths": [
["browserAction"]
@ -143,6 +144,7 @@
"url": "chrome://browser/content/parent/ext-pageAction.js",
"schema": "chrome://extensions/content/schemas/page_action.json",
"scopes": ["addon_parent"],
"events": ["update", "uninstall", "disable"],
"manifest": ["page_action"],
"paths": [
["pageAction"]

Просмотреть файл

@ -31,6 +31,11 @@ ChromeUtils.defineModuleGetter(
"ViewPopup",
"resource:///modules/ExtensionPopups.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUsageTelemetry",
"resource:///modules/BrowserUsageTelemetry.jsm"
);
var { DefaultWeakMap } = ExtensionUtils;
@ -57,6 +62,10 @@ XPCOMUtils.defineLazyGetter(this, "browserAreas", () => {
};
});
function actionWidgetId(widgetId) {
return `${widgetId}-browser-action`;
}
class BrowserAction extends BrowserActionBase {
constructor(extension, buttonDelegate) {
let tabContext = new TabContext(target => {
@ -122,7 +131,7 @@ this.browserAction = class extends ExtensionAPI {
);
let widgetId = makeWidgetId(extension.id);
this.id = `${widgetId}-browser-action`;
this.id = actionWidgetId(widgetId);
this.viewId = `PanelUI-webext-${widgetId}-browser-action-view`;
this.widget = null;
@ -138,6 +147,37 @@ this.browserAction = class extends ExtensionAPI {
this.build();
}
static onUpdate(id, manifest) {
if (!("browser_action" in manifest)) {
// If the new version has no browser action then mark this widget as
// hidden in the telemetry. If it is already marked hidden then this will
// do nothing.
BrowserUsageTelemetry.recordWidgetChange(
actionWidgetId(makeWidgetId(id)),
null,
"addon"
);
}
}
static onDisable(id) {
BrowserUsageTelemetry.recordWidgetChange(
actionWidgetId(makeWidgetId(id)),
null,
"addon"
);
}
static onUninstall(id) {
// If the telemetry already has this widget as hidden then this will not
// record anything.
BrowserUsageTelemetry.recordWidgetChange(
actionWidgetId(makeWidgetId(id)),
null,
"addon"
);
}
onShutdown() {
browserActionMap.delete(this.extension);
this.action.onShutdown();
@ -268,6 +308,19 @@ this.browserAction = class extends ExtensionAPI {
},
});
if (this.extension.startupReason != "APP_STARTUP") {
// Make sure the browser telemetry has the correct state for this widget.
// Defer loading BrowserUsageTelemetry until after startup is complete.
ExtensionParent.browserStartupPromise.then(() => {
let placement = CustomizableUI.getPlacementOfWidget(widget.id);
BrowserUsageTelemetry.recordWidgetChange(
widget.id,
placement?.area || null,
"addon"
);
});
}
this.widget = widget;
}

Просмотреть файл

@ -21,9 +21,17 @@ ChromeUtils.defineModuleGetter(
"PanelPopup",
"resource:///modules/ExtensionPopups.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUsageTelemetry",
"resource:///modules/BrowserUsageTelemetry.jsm"
);
var { DefaultWeakMap } = ExtensionUtils;
var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
);
var { PageActionBase } = ChromeUtils.import(
"resource://gre/modules/ExtensionActions.jsm"
);
@ -55,6 +63,25 @@ this.pageAction = class extends ExtensionAPI {
return pageActionMap.get(extension);
}
static onUpdate(id, manifest) {
if (!("page_action" in manifest)) {
// If the new version has no page action then mark this widget as hidden
// in the telemetry. If it is already marked hidden then this will do
// nothing.
BrowserUsageTelemetry.recordWidgetChange(makeWidgetId(id), null, "addon");
}
}
static onDisable(id) {
BrowserUsageTelemetry.recordWidgetChange(makeWidgetId(id), null, "addon");
}
static onUninstall(id) {
// If the telemetry already has this widget as hidden then this will not
// record anything.
BrowserUsageTelemetry.recordWidgetChange(makeWidgetId(id), null, "addon");
}
async onManifestEntry(entryName) {
let { extension } = this;
let options = extension.manifest.page_action;
@ -127,6 +154,20 @@ this.pageAction = class extends ExtensionAPI {
})
);
if (this.extension.startupReason != "APP_STARTUP") {
// Make sure the browser telemetry has the correct state for this widget.
// Defer loading BrowserUsageTelemetry until after startup is complete.
ExtensionParent.browserStartupPromise.then(() => {
BrowserUsageTelemetry.recordWidgetChange(
widgetId,
this.browserPageAction.pinnedToUrlbar
? "page-action-buttons"
: null,
"addon"
);
});
}
// If the page action is only enabled in some URLs, do pattern matching in
// the active tabs and update the button if necessary.
if (this.action.getProperty(null, "enabled") === undefined) {

Просмотреть файл

@ -59,6 +59,11 @@ ChromeUtils.defineModuleGetter(
"UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUsageTelemetry",
"resource:///modules/BrowserUsageTelemetry.jsm"
);
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
const PREF_LOG_LEVEL = "browser.uitour.loglevel";
@ -2003,6 +2008,11 @@ var UITour = {
aTarget.widgetName,
CustomizableUI.AREA_NAVBAR
);
BrowserUsageTelemetry.recordWidgetChange(
aTarget.widgetName,
CustomizableUI.AREA_NAVBAR,
"uitour"
);
this.sendPageCallback(aBrowser, aCallbackID);
},

Просмотреть файл

@ -1889,6 +1889,7 @@ class UrlbarInput {
}
let pasteAndGo = this.document.createXULElement("menuitem");
pasteAndGo.id = "paste-and-go";
let label = Services.strings
.createBundle("chrome://browser/locale/browser.properties")
.GetStringFromName("pasteAndGo.label");

Просмотреть файл

@ -16,9 +16,9 @@ As the transition to the ``BrowserUsageTelemetry`` happens, the ``recordSearch``
A list of the components recording search Telemetry can be found using the following `DXR search <https://dxr.mozilla.org/mozilla-central/search?q=recordSearchInTelemetry>`_.
Measured interactions
=====================
The usage telemetry module currently measures these interactions with the browser:
Tab and window interactions
===========================
The usage telemetry module currently measures these interactions with the browser's tabs and windows:
- *tab and window engagement*: counts the number of non-private tabs and windows opened in a subsession, after the session is restored (see e.g. ``browser.engagement.max_concurrent_tab_count``);
- *URI loads*: counts the number of page loads (doesn't track and send the addresses, just the counts) directly triggered by the users (see ``browser.engagement.total_uri_count``);
@ -26,3 +26,96 @@ The usage telemetry module currently measures these interactions with the browse
Please see `Scalars.yaml <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ for the full list of tracked interactions.
Customizable UI
===============
This telemetry records information about the positions of toolbar items and when
the user interacts with them. It is submitted as scalar values along with the
normal telemetry ping. There are a number of different parts to this telemetry:
UI Areas
--------
For the purposes of this telemetry a set of areas are defined:
* In the main browser UI:
* ``menu-bar`` - The main menu.
* ``menu-toolbar`` - The normally hidden toolbar that holds the main menu.
* ``drag-space`` - The optional drag space.
* ``titlebar`` - The optional title bar.
* ``tabs-bar`` - The area where tabs are displayed.
* ``bookmarks-bar`` - The bookmarks toolbar.
* ``app-menu`` - The main application (hamburger) menu.
* ``tabs-context`` - The context menu shown from right-clicking a tab.
* ``content-context`` - The context menu shown from right-clicking the web page.
* ``widget-overflow-list`` - Items that have overflowed the available space.
* ``pinned-overflow-menu`` - Items that the user has pinned to the toolbar overflow menu.
* ``pageaction-urlbar`` - Page actions buttons in the address bar.
* ``pageaction-panel`` - The page action (meatball) menu.
* ``nav-bar-start`` - The area of the navigation toolbar before the address bar.
* ``nav-bar-end`` - The area of the navigastion toolbar after the address bar.
* In ``about:preferences`` the different cagtegories are used:
* ``preferences-paneGeneral``
* ``preferences-paneHome``
* ``preferences-panePrivacy``
* ``preferences-paneSearch``
* ``preferences-paneSearchResults``
* ``preferences-paneSync``
* ``preferences-paneContainers``
Widget Identifiers
------------------
In order to uniquely identify a visual element a set of heuristics are used:
#. If the element is one of the customizable toolbar items then that item's ID
is used.
#. If the DOM element has an ID set then that is used.
#. If the DOM element's class contains one of ``bookmark-item``,
``tab-icon-sound`` or ``tab-close-button`` then that is used.
#. If the DOM element has a ``preference`` ``key``, ``command``, ``observes`` or
``data-l10n-id`` attribute then that is used.
#. If there is still no identifier then this is repeated for the DOM element's
parent element.
Widget Locations
----------------
The keyed scalar ``browser.ui.toolbar_widgets`` records the position of widgets in
the UI. At startup the positions of widgets are collected and recorded by
setting the scalar key ``<widget id>_pinned_<area>`` to true. The widget ID are
the IDs of the elements in the DOM. The area is one of the areas listed above
from the browser UI that can be customised.
For the areas that can be controlled the scalar keys ``<area>_<off/on>`` are set.
Widget Customization
--------------------
The scalar ``browser.ui.customized_widgets`` records whenever the user moves a
widget around the toolbars or shows or hides some of the areas. When a change
occurs the scalar with the key ``<widget id>_<action>_<old area>_<new area>_<reason>``
is incremented. The action can be one of ``move``, ``add`` or ``remove``. Old
area and new area are the previous and now locations of the widget. In the case
of ``add`` or ``remove`` actions one of the areas will be ``na``. For areas that
can be shown or hidden the areas will be ``off`` or ``on``. The reason is a simple
string that indicates what caused the move to happen (drag, context menu, etc.).
UI Interactions
---------------
The scalars ``browser.ui.interaction.<area>`` record how often the use
interacts with the browser. The area is one of those above with the addition of
``keyboard`` for keyboard shortcuts.
When an interaction occurs the widget's identifier is used as the key and the
scalar is incremented. If the widget is provided by an add-on then the add-on
identifier is dropped and an identifier of the form ``addonX`` is used where X
is a number. The number used is stable for a single session. Everytime the user
moves or interacts with an add-on the same number is used but then the numbers
for each add-on may change after Firefox has been restarted.

Просмотреть файл

@ -19,6 +19,9 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
CustomizableUI: "resource:///modules/CustomizableUI.jsm",
PageActions: "resource:///modules/PageActions.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
SearchTelemetry: "resource:///modules/SearchTelemetry.jsm",
Services: "resource://gre/modules/Services.jsm",
@ -118,6 +121,80 @@ const URLBAR_SELECTED_RESULT_METHODS = {
const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms
// The elements we consider to be interactive.
const UI_TARGET_ELEMENTS = [
"menuitem",
"toolbarbutton",
"key",
"command",
"checkbox",
"input",
"button",
"image",
"radio",
"richlistitem",
];
// The containers of interactive elements that we care about and their pretty
// names. These should be listed in order of most-specific to least-specific,
// when iterating JavaScript will guarantee that ordering and so we will find
// the most specific area first.
const BROWSER_UI_CONTAINER_IDS = {
"toolbar-menubar": "menu-bar",
TabsToolbar: "tabs-bar",
PersonalToolbar: "bookmarks-bar",
"appMenu-popup": "app-menu",
tabContextMenu: "tabs-context",
contentAreaContextMenu: "content-context",
"widget-overflow-list": "overflow-menu",
"widget-overflow-fixed-list": "pinned-overflow-menu",
"page-action-buttons": "pageaction-urlbar",
pageActionPanel: "pageaction-panel",
// This should appear last as some of the above are inside the nav bar.
"nav-bar": "nav-bar",
};
const IGNORABLE_EVENTS = new WeakMap();
const KNOWN_ADDONS = [];
function telemetryId(widgetId, obscureAddons = true) {
// Add-on IDs need to be obscured.
function addonId(id) {
if (!obscureAddons) {
return id;
}
let pos = KNOWN_ADDONS.indexOf(id);
if (pos < 0) {
pos = KNOWN_ADDONS.length;
KNOWN_ADDONS.push(id);
}
return `addon${pos}`;
}
if (widgetId.endsWith("-browser-action")) {
widgetId = addonId(
widgetId.substring(0, widgetId.length - "-browser-action".length)
);
} else if (widgetId.startsWith("pageAction-")) {
let actionId;
if (widgetId.startsWith("pageAction-urlbar-")) {
actionId = widgetId.substring("pageAction-urlbar-".length);
} else if (widgetId.startsWith("pageAction-panel-")) {
actionId = widgetId.substring("pageAction-panel-".length);
}
if (actionId) {
let action = PageActions.actionForID(actionId);
widgetId = action?._isMozillaAction ? actionId : addonId(actionId);
}
}
return widgetId.replace(/_/g, "-");
}
function getOpenTabsAndWinsCounts() {
let loadedTabCount = 0;
let tabCount = 0;
@ -337,6 +414,18 @@ let BrowserUsageTelemetry = {
this._lastRecordLoadedTabCount = 0;
this._setupAfterRestore();
this._inited = true;
Services.prefs.addObserver("browser.tabs.extraDragSpace", this);
Services.prefs.addObserver("browser.tabs.drawInTitlebar", this);
this._recordUITelemetry();
},
/**
* Resets the masked add-on identifiers. Only for use in tests.
*/
_resetAddonIds() {
KNOWN_ADDONS.length = 0;
},
/**
@ -381,6 +470,28 @@ let BrowserUsageTelemetry = {
case TELEMETRY_SUBSESSIONSPLIT_TOPIC:
this.afterSubsessionSplit();
break;
case "nsPref:changed":
switch (data) {
case "browser.tabs.extraDragSpace":
this._recordWidgetChange(
"drag-space",
Services.prefs.getBoolPref("browser.tabs.extraDragSpace")
? "on"
: "off",
"pref"
);
break;
case "browser.tabs.drawInTitlebar":
this._recordWidgetChange(
"titlebar",
Services.prefs.getBoolPref("browser.tabs.drawInTitlebar")
? "off"
: "on",
"pref"
);
break;
}
break;
}
},
@ -669,10 +780,367 @@ let BrowserUsageTelemetry = {
);
},
_buildWidgetPositions() {
let widgetMap = new Map();
const toolbarState = nodeId => {
let value = Services.xulStore.getValue(
AppConstants.BROWSER_CHROME_URL,
nodeId,
"collapsed"
);
if (value) {
return value == "true" ? "off" : "on";
}
return "off";
};
widgetMap.set(
BROWSER_UI_CONTAINER_IDS.PersonalToolbar,
toolbarState("PersonalToolbar")
);
let menuBarHidden =
Services.xulStore.getValue(
AppConstants.BROWSER_CHROME_URL,
"toolbar-menubar",
"autohide"
) != "false";
widgetMap.set("menu-toolbar", menuBarHidden ? "off" : "on");
widgetMap.set(
"drag-space",
Services.prefs.getBoolPref("browser.tabs.extraDragSpace") ? "on" : "off"
);
// Drawing in the titlebar means not showing the titlebar, hence the negation.
widgetMap.set(
"titlebar",
Services.prefs.getBoolPref("browser.tabs.drawInTitlebar", true)
? "off"
: "on"
);
for (let area of CustomizableUI.areas) {
if (!(area in BROWSER_UI_CONTAINER_IDS)) {
continue;
}
let position = BROWSER_UI_CONTAINER_IDS[area];
if (area == "nav-bar") {
position = `${BROWSER_UI_CONTAINER_IDS[area]}-start`;
}
let widgets = CustomizableUI.getWidgetsInArea(area);
for (let widget of widgets) {
if (!widget) {
continue;
}
if (widget.id.startsWith("customizableui-special-")) {
continue;
}
if (area == "nav-bar" && widget.id == "urlbar-container") {
position = `${BROWSER_UI_CONTAINER_IDS[area]}-end`;
continue;
}
widgetMap.set(widget.id, position);
}
}
let actions = PageActions.actions;
for (let action of actions) {
if (action.pinnedToUrlbar) {
widgetMap.set(action.id, "pageaction-urlbar");
}
}
return widgetMap;
},
_getWidgetID(node) {
// We want to find a sensible ID for this element.
if (!node) {
return null;
}
// See if this is a customizable widget.
if (node.ownerDocument.URL == AppConstants.BROWSER_CHROME_URL) {
// First find if it is inside one of the customizable areas.
for (let area of CustomizableUI.areas) {
if (node.closest(`#${area}`)) {
for (let widget of CustomizableUI.getWidgetIdsInArea(area)) {
if (
// We care about the buttons on the tabs themselves.
widget == "tabbrowser-tabs" ||
// We care about the page action and other buttons in here.
widget == "urlbar-container" ||
// We care about individual bookmarks here.
widget == "personal-bookmarks"
) {
continue;
}
if (node.closest(`#${widget}`)) {
return widget;
}
}
break;
}
}
}
if (node.id) {
return node.id;
}
// A couple of special cases in the tabs.
for (let cls of ["bookmark-item", "tab-icon-sound", "tab-close-button"]) {
if (node.classList.contains(cls)) {
return cls;
}
}
// One of these will at least let us know what the widget is for.
for (let idAttribute of [
"preference",
"key",
"command",
"observes",
"data-l10n-id",
]) {
if (node.hasAttribute(idAttribute)) {
return node.getAttribute(idAttribute);
}
}
return this._getWidgetID(node.parentElement);
},
_getWidgetContainer(node) {
if (node.localName == "key") {
return "keyboard";
}
if (node.ownerDocument.URL == AppConstants.BROWSER_CHROME_URL) {
// Find the container holding this element.
for (let containerId of Object.keys(BROWSER_UI_CONTAINER_IDS)) {
let container = node.ownerDocument.getElementById(containerId);
if (container && container.contains(node)) {
return BROWSER_UI_CONTAINER_IDS[containerId];
}
}
} else if (node.ownerDocument.URL.startsWith("about:preferences")) {
// Find the element's category.
let container = node.closest("[data-category]");
if (!container) {
return null;
}
return `preferences_${container.getAttribute("data-category")}`;
}
return null;
},
lastClickTarget: null,
ignoreEvent(event) {
IGNORABLE_EVENTS.set(event, true);
},
_recordCommand(event) {
if (IGNORABLE_EVENTS.get(event)) {
return;
}
let types = [event.type];
let sourceEvent = event;
while (sourceEvent.sourceEvent) {
sourceEvent = sourceEvent.sourceEvent;
types.push(sourceEvent.type);
}
let lastTarget = this.lastClickTarget?.get();
if (
lastTarget &&
sourceEvent.type == "command" &&
sourceEvent.target.contains(lastTarget)
) {
// Ignore a command event triggered by a click.
this.lastClickTarget = null;
return;
}
this.lastClickTarget = null;
if (sourceEvent.type == "click") {
// Only care about main button clicks.
if (sourceEvent.button != 0) {
return;
}
// This click may trigger a command event so retain the target to be able
// to dedupe that event.
this.lastClickTarget = Cu.getWeakReference(sourceEvent.target);
}
// We should never see events from web content as they are fired in a
// content process, but let's be safe.
let url = sourceEvent.target.ownerDocument.documentURIObject;
if (!url.schemeIs("chrome") && !url.schemeIs("about")) {
return;
}
// This is what events targetted at content will actually look like.
if (sourceEvent.target.localName == "browser") {
return;
}
// Find the actual element we're interested in.
let node = sourceEvent.target;
while (!UI_TARGET_ELEMENTS.includes(node.localName)) {
node = node.parentNode;
if (!node) {
// A click on a space or label or something we're not interested in.
return;
}
}
let item = this._getWidgetID(node);
let source = this._getWidgetContainer(node);
if (item && source) {
let scalar = `browser.ui.interaction.${source.replace("-", "_")}`;
Services.telemetry.keyedScalarAdd(scalar, telemetryId(item), 1);
}
},
/**
* Listens for UI interactions in the window.
*/
_addUsageListeners(win) {
// Listen for command events from the UI.
win.addEventListener("command", event => this._recordCommand(event), true);
win.addEventListener("click", event => this._recordCommand(event), true);
},
/**
* A public version of the private method to take care of the `nav-bar-start`,
* `nav-bar-end` thing that callers shouldn't have to care about. It also
* accepts the DOM ids for the areas rather than the cleaner ones we report
* to telemetry.
*/
recordWidgetChange(widgetId, newPos, reason) {
try {
if (newPos) {
newPos = BROWSER_UI_CONTAINER_IDS[newPos];
}
if (newPos == "nav-bar") {
let { position } = CustomizableUI.getPlacementOfWidget(widgetId);
let { position: urlPosition } = CustomizableUI.getPlacementOfWidget(
"urlbar-container"
);
newPos = newPos + (urlPosition > position ? "-start" : "-end");
}
this._recordWidgetChange(widgetId, newPos, reason);
} catch (e) {
console.error(e);
}
},
recordToolbarVisibility(toolbarId, newState, reason) {
this._recordWidgetChange(
BROWSER_UI_CONTAINER_IDS[toolbarId],
newState ? "on" : "off",
reason
);
},
_recordWidgetChange(widgetId, newPos, reason) {
// In some cases (like when add-ons are detected during startup) this gets
// called before we've reported the initial positions. Ignore such cases.
if (!this.widgetMap) {
return;
}
if (widgetId == "urlbar-container") {
// We don't report the position of the url bar, it is after nav-bar-start
// and before nav-bar-end. But moving it means the widgets around it have
// effectively moved so update those.
let position = "nav-bar-start";
let widgets = CustomizableUI.getWidgetsInArea("nav-bar");
for (let widget of widgets) {
if (!widget) {
continue;
}
if (widget.id.startsWith("customizableui-special-")) {
continue;
}
if (widget.id == "urlbar-container") {
position = "nav-bar-end";
continue;
}
// This will do nothing if the position hasn't changed.
this._recordWidgetChange(widget.id, position, reason);
}
return;
}
let oldPos = this.widgetMap.get(widgetId);
if (oldPos == newPos) {
return;
}
let action = "move";
if (!oldPos) {
action = "add";
} else if (!newPos) {
action = "remove";
}
let key = `${telemetryId(widgetId, false)}_${action}_${oldPos ??
"na"}_${newPos ?? "na"}_${reason}`;
Services.telemetry.keyedScalarAdd("browser.ui.customized_widgets", key, 1);
if (newPos) {
this.widgetMap.set(widgetId, newPos);
} else {
this.widgetMap.delete(widgetId);
}
},
_recordUITelemetry() {
this.widgetMap = this._buildWidgetPositions();
for (let [widgetId, position] of this.widgetMap.entries()) {
let key = `${telemetryId(widgetId, false)}_pinned_${position}`;
Services.telemetry.keyedScalarSet(
"browser.ui.toolbar_widgets",
key,
true
);
}
},
/**
* Adds listeners to a single chrome window.
*/
_registerWindow(win) {
this._addUsageListeners(win);
win.addEventListener("unload", this);
win.addEventListener("TabOpen", this, true);
win.addEventListener("TabPinned", this, true);

Просмотреть файл

@ -41,8 +41,10 @@ skip-if = fission && !webrender # Two startup notifications, this confuses the t
skip-if = (os == "mac") || (!debug && os == "linux" && bits == 64 && os_version == "18.04") # Bug 1528429
[browser_UsageTelemetry.js]
[browser_UsageTelemetry_domains.js]
[browser_UsageTelemetry_interaction.js]
[browser_UsageTelemetry_private_and_restore.js]
skip-if = verify && debug
[browser_UsageTelemetry_toolbars.js]
[browser_UsageTelemetry_uniqueOriginsVisitedInPast24Hours.js]
[browser_UsageTelemetry_urlbar_extension.js]
[browser_UsageTelemetry_urlbar_places.js]

Просмотреть файл

@ -0,0 +1,399 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
gReduceMotionOverride = true;
const AREAS = [
"keyboard",
"menu_bar",
"tabs_bar",
"nav_bar",
"bookmarks_bar",
"app_menu",
"tabs_context",
"content_context",
"overflow_menu",
"pinned_overflow_menu",
"pageaction_urlbar",
"pageaction_panel",
"preferences_paneHome",
"preferences_paneGeneral",
"preferences_panePrivacy",
"preferences_paneSearch",
"preferences_paneSearchResults",
"preferences_paneSync",
"preferences_paneContainers",
];
// Checks that the correct number of clicks are registered against the correct
// keys in the scalars.
function assertInteractionScalars(expectedAreas) {
let processScalars =
Services.telemetry.getSnapshotForKeyedScalars("main", true)?.parent ?? {};
for (let source of AREAS) {
let scalars = processScalars?.[`browser.ui.interaction.${source}`] ?? {};
let expected = expectedAreas[source] ?? {};
let expectedKeys = new Set(
Object.keys(scalars).concat(Object.keys(expected))
);
for (let key of expectedKeys) {
Assert.equal(
scalars[key],
expected[key],
`Expected to see the correct value for ${key} in ${source}.`
);
}
}
}
const elem = id => document.getElementById(id);
const click = el => {
if (typeof el == "string") {
el = elem(el);
}
EventUtils.synthesizeMouseAtCenter(el, {}, window);
};
add_task(async function toolbarButtons() {
await BrowserTestUtils.withNewTab("http://example.com", async () => {
Services.telemetry.getSnapshotForKeyedScalars("main", true);
let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
let tabClose = BrowserTestUtils.waitForTabClosing(newTab);
let transition = BrowserTestUtils.waitForTransition(
elem("PersonalToolbar")
);
CustomizableUI.setToolbarVisibility("PersonalToolbar", true);
registerCleanupFunction(() => {
CustomizableUI.setToolbarVisibility("PersonalToolbar", false);
});
await transition;
let tabs = elem("tabbrowser-tabs");
if (!tabs.hasAttribute("overflow")) {
tabs.setAttribute("overflow", "true");
registerCleanupFunction(() => {
tabs.removeAttribute("overflow");
});
}
click("stop-reload-button");
click("back-button");
click("back-button");
// Make sure the all tabs panel is in the document.
gTabsPanel.initElements();
let view = elem("allTabsMenu-allTabsView");
let shown = BrowserTestUtils.waitForEvent(view, "ViewShown");
click("alltabs-button");
await shown;
let hidden = BrowserTestUtils.waitForEvent(view, "ViewHiding");
gTabsPanel.hideAllTabsPanel();
await hidden;
click(newTab.querySelector(".tab-close-button"));
await tabClose;
click(document.querySelector("#PlacesToolbarItems .bookmark-item"));
let pagePanel = elem("pageActionPanel");
shown = BrowserTestUtils.waitForEvent(pagePanel, "popupshown");
click("pageActionButton");
await shown;
hidden = BrowserTestUtils.waitForEvent(pagePanel, "popuphidden");
click("pageAction-panel-copyURL");
await hidden;
assertInteractionScalars({
nav_bar: {
"stop-reload-button": 1,
"back-button": 2,
},
tabs_bar: {
"alltabs-button": 1,
"tab-close-button": 1,
},
bookmarks_bar: {
"bookmark-item": 1,
},
pageaction_urlbar: {
pageActionButton: 1,
},
pageaction_panel: {
copyURL: 1,
},
});
});
});
add_task(async function contextMenu() {
await BrowserTestUtils.withNewTab("http://example.com", async browser => {
Services.telemetry.getSnapshotForKeyedScalars("main", true);
let tab = gBrowser.getTabForBrowser(browser);
let context = elem("tabContextMenu");
let shown = BrowserTestUtils.waitForEvent(context, "popupshown");
EventUtils.synthesizeMouseAtCenter(
tab,
{ type: "contextmenu", button: 2 },
window
);
await shown;
let hidden = BrowserTestUtils.waitForEvent(context, "popuphidden");
click("context_toggleMuteTab");
await hidden;
assertInteractionScalars({
tabs_context: {
"context-toggleMuteTab": 1,
},
});
});
});
add_task(async function appMenu() {
await BrowserTestUtils.withNewTab("http://example.com", async browser => {
Services.telemetry.getSnapshotForKeyedScalars("main", true);
let shown = BrowserTestUtils.waitForEvent(
elem("appMenu-popup"),
"popupshown"
);
click("PanelUI-menu-button");
await shown;
let hidden = BrowserTestUtils.waitForEvent(
elem("appMenu-popup"),
"popuphidden"
);
click("appMenu-find-button");
await hidden;
assertInteractionScalars({
nav_bar: {
"PanelUI-menu-button": 1,
},
app_menu: {
"appMenu-find-button": 1,
},
});
});
});
add_task(async function devtools() {
await BrowserTestUtils.withNewTab("http://example.com", async browser => {
Services.telemetry.getSnapshotForKeyedScalars("main", true);
let shown = BrowserTestUtils.waitForEvent(
elem("appMenu-popup"),
"popupshown"
);
click("PanelUI-menu-button");
await shown;
shown = BrowserTestUtils.waitForEvent(
elem("PanelUI-developer"),
"ViewShown"
);
click("appMenu-developer-button");
await shown;
let tabOpen = BrowserTestUtils.waitForNewTab(gBrowser);
let hidden = BrowserTestUtils.waitForEvent(
elem("appMenu-popup"),
"popuphidden"
);
click(
document.querySelector(
"#PanelUI-developer toolbarbutton[key='key_viewSource']"
)
);
await hidden;
let tab = await tabOpen;
BrowserTestUtils.removeTab(tab);
// Note that item ID's have '_' converted to '-'.
assertInteractionScalars({
nav_bar: {
"PanelUI-menu-button": 1,
},
app_menu: {
"appMenu-developer-button": 1,
"key-viewSource": 1,
},
});
});
});
add_task(async function webextension() {
BrowserUsageTelemetry._resetAddonIds();
await BrowserTestUtils.withNewTab("http://example.com", async browser => {
Services.telemetry.getSnapshotForKeyedScalars("main", true);
const extension = ExtensionTestUtils.loadExtension({
manifest: {
version: "1",
applications: {
gecko: { id: "random_addon@example.com" },
},
browser_action: {
default_icon: "default.png",
default_title: "Hello",
},
page_action: {
default_icon: "default.png",
default_title: "Hello",
show_matches: ["http://example.com/*"],
},
},
});
await extension.startup();
// As the first add-on interacted with this should show up as `addon0`.
click("random_addon_example_com-browser-action");
assertInteractionScalars({
nav_bar: {
addon0: 1,
},
});
// Wait for the element to show up.
await TestUtils.waitForCondition(() =>
elem("pageAction-urlbar-random_addon_example_com")
);
click("pageAction-urlbar-random_addon_example_com");
assertInteractionScalars({
pageaction_urlbar: {
addon0: 1,
},
});
const extension2 = ExtensionTestUtils.loadExtension({
manifest: {
version: "1",
applications: {
gecko: { id: "random_addon2@example.com" },
},
browser_action: {
default_icon: "default.png",
default_title: "Hello",
},
page_action: {
default_icon: "default.png",
default_title: "Hello",
show_matches: ["http://example.com/*"],
},
},
});
await extension2.startup();
// A second extension should be `addon1`.
click("random_addon2_example_com-browser-action");
assertInteractionScalars({
nav_bar: {
addon1: 1,
},
});
// Wait for the element to show up.
await TestUtils.waitForCondition(() =>
elem("pageAction-urlbar-random_addon2_example_com")
);
click("pageAction-urlbar-random_addon2_example_com");
assertInteractionScalars({
pageaction_urlbar: {
addon1: 1,
},
});
// The first should have retained its ID.
click("random_addon_example_com-browser-action");
assertInteractionScalars({
nav_bar: {
addon0: 1,
},
});
click("pageAction-urlbar-random_addon_example_com");
assertInteractionScalars({
pageaction_urlbar: {
addon0: 1,
},
});
await extension.unload();
// The second should retain its ID.
click("random_addon2_example_com-browser-action");
click("random_addon2_example_com-browser-action");
assertInteractionScalars({
nav_bar: {
addon1: 2,
},
});
click("pageAction-urlbar-random_addon2_example_com");
assertInteractionScalars({
pageaction_urlbar: {
addon1: 1,
},
});
await extension2.unload();
});
});
add_task(async function preferences() {
let initialized = BrowserTestUtils.waitForEvent(gBrowser, "Initialized");
await BrowserTestUtils.withNewTab("about:preferences", async browser => {
await initialized;
Services.telemetry.getSnapshotForKeyedScalars("main", true);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#browserRestoreSession",
{},
gBrowser.selectedBrowser.browsingContext
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#category-search",
{},
gBrowser.selectedBrowser.browsingContext
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#searchBarShownRadio",
{},
gBrowser.selectedBrowser.browsingContext
);
assertInteractionScalars({
preferences_paneGeneral: {
browserRestoreSession: 1,
},
preferences_paneSearch: {
searchBarShownRadio: 1,
},
});
});
});

Просмотреть файл

@ -0,0 +1,642 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
gReduceMotionOverride = true;
function enterCustomizationMode(win = window) {
let customizationReadyPromise = BrowserTestUtils.waitForEvent(
win.gNavToolbox,
"customizationready"
);
win.gCustomizeMode.enter();
return customizationReadyPromise;
}
function leaveCustomizationMode(win = window) {
let customizationDonePromise = BrowserTestUtils.waitForEvent(
win.gNavToolbox,
"aftercustomization"
);
win.gCustomizeMode.exit();
return customizationDonePromise;
}
Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
registerCleanupFunction(() =>
Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck")
);
// Stolen from browser/components/customizableui/tests/browser/head.js
function simulateItemDrag(aToDrag, aTarget, aEvent = {}, aOffset = 2) {
let ev = aEvent;
if (ev == "end" || ev == "start") {
let win = aTarget.ownerGlobal;
const dwu = win.windowUtils;
let bounds = dwu.getBoundsWithoutFlushing(aTarget);
if (ev == "end") {
ev = {
clientX: bounds.right - aOffset,
clientY: bounds.bottom - aOffset,
};
} else {
ev = { clientX: bounds.left + aOffset, clientY: bounds.top + aOffset };
}
}
ev._domDispatchOnly = true;
EventUtils.synthesizeDrop(
aToDrag.parentNode,
aTarget,
null,
null,
aToDrag.ownerGlobal,
aTarget.ownerGlobal,
ev
);
// Ensure dnd suppression is cleared.
EventUtils.synthesizeMouseAtCenter(
aTarget,
{ type: "mouseup" },
aTarget.ownerGlobal
);
}
function organizeToolbars(state = {}) {
// Set up the defaults for the state.
let targetState = Object.assign(
{
// Areas where widgets can be placed, set to an array of widget IDs.
"toolbar-menubar": undefined,
PersonalToolbar: undefined,
TabsToolbar: ["tabbrowser-tabs", "alltabs-button"],
"widget-overflow-fixed-list": undefined,
"nav-bar": ["back-button", "forward-button", "urlbar-container"],
// The page action's that should be in the URL bar.
pageActionsInUrlBar: [],
// Areas to show or hide.
dragSpaceVisible: false,
titlebarVisible: false,
menubarVisible: false,
personalToolbarVisible: false,
},
state
);
for (let area of CustomizableUI.areas) {
// Clear out anything there already.
for (let widgetId of CustomizableUI.getWidgetIdsInArea(area)) {
CustomizableUI.removeWidgetFromArea(widgetId);
}
if (targetState[area]) {
// We specify the position explicitly to support the toolbars that have
// fixed widgets.
let position = 0;
for (let widgetId of targetState[area]) {
CustomizableUI.addWidgetToArea(widgetId, area, position++);
}
}
}
CustomizableUI.setToolbarVisibility(
"toolbar-menubar",
targetState.menubarVisible
);
CustomizableUI.setToolbarVisibility(
"PersonalToolbar",
targetState.personalToolbarVisible
);
Services.prefs.setBoolPref(
"browser.tabs.extraDragSpace",
!targetState.titlebarVisible && targetState.dragSpaceVisible
);
Services.prefs.setBoolPref(
"browser.tabs.drawInTitlebar",
!targetState.titlebarVisible
);
for (let action of PageActions.actions) {
action.pinnedToUrlbar = targetState.pageActionsInUrlBar.includes(action.id);
}
// Clear out the existing telemetry.
Services.telemetry.getSnapshotForKeyedScalars("main", true);
}
function assertVisibilityScalars(expected) {
let scalars =
Services.telemetry.getSnapshotForKeyedScalars("main", true)?.parent?.[
"browser.ui.toolbar_widgets"
] ?? {};
// Only some platforms have the menubar items.
if (AppConstants.MENUBAR_CAN_AUTOHIDE) {
expected.push("menubar-items_pinned_menu-bar");
}
let keys = new Set(expected.concat(Object.keys(scalars)));
for (let key of keys) {
Assert.ok(expected.includes(key), `Scalar key ${key} was unexpected.`);
Assert.ok(scalars[key], `Expected to see see scalar key ${key} be true.`);
}
}
function assertCustomizeScalars(expected) {
let scalars =
Services.telemetry.getSnapshotForKeyedScalars("main", true)?.parent?.[
"browser.ui.customized_widgets"
] ?? {};
let keys = new Set(Object.keys(expected).concat(Object.keys(scalars)));
for (let key of keys) {
Assert.equal(
scalars[key],
expected[key],
`Expected to see the correct value for scalar ${key}.`
);
}
}
add_task(async function widgetPositions() {
organizeToolbars();
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
]);
organizeToolbars({
PersonalToolbar: [
"fxa-toolbar-menu-button",
"new-tab-button",
"developer-button",
],
TabsToolbar: [
"stop-reload-button",
"tabbrowser-tabs",
"personal-bookmarks",
],
"nav-bar": [
"home-button",
"forward-button",
"downloads-button",
"urlbar-container",
"back-button",
"library-button",
],
dragSpaceVisible: true,
personalToolbarVisible: true,
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_on",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_on",
"tabbrowser-tabs_pinned_tabs-bar",
"stop-reload-button_pinned_tabs-bar",
"personal-bookmarks_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"home-button_pinned_nav-bar-start",
"forward-button_pinned_nav-bar-start",
"downloads-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-end",
"library-button_pinned_nav-bar-end",
"fxa-toolbar-menu-button_pinned_bookmarks-bar",
"new-tab-button_pinned_bookmarks-bar",
"developer-button_pinned_bookmarks-bar",
]);
CustomizableUI.reset();
});
add_task(async function customizeMode() {
// Create a default state.
organizeToolbars({
PersonalToolbar: ["personal-bookmarks"],
TabsToolbar: ["tabbrowser-tabs", "new-tab-button"],
"nav-bar": [
"back-button",
"forward-button",
"stop-reload-button",
"urlbar-container",
"home-button",
"library-button",
],
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"new-tab-button_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"back-button_pinned_nav-bar-start",
"forward-button_pinned_nav-bar-start",
"stop-reload-button_pinned_nav-bar-start",
"home-button_pinned_nav-bar-end",
"library-button_pinned_nav-bar-end",
"personal-bookmarks_pinned_bookmarks-bar",
]);
let win = await BrowserTestUtils.openNewBrowserWindow();
await enterCustomizationMode(win);
let toolbarButton = win.document.getElementById(
"customization-toolbar-visibility-button"
);
let toolbarPopup = win.document.getElementById("customization-toolbar-menu");
let popupShown = BrowserTestUtils.waitForEvent(toolbarPopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await popupShown;
let popupHidden = BrowserTestUtils.waitForEvent(toolbarPopup, "popuphidden");
let barButton = win.document.getElementById("toggle_PersonalToolbar");
EventUtils.synthesizeMouseAtCenter(barButton, {}, win);
await popupHidden;
let navbar = CustomizableUI.getCustomizationTarget(
win.document.getElementById("nav-bar")
);
let bookmarksBar = CustomizableUI.getCustomizationTarget(
win.document.getElementById("PersonalToolbar")
);
let tabBar = CustomizableUI.getCustomizationTarget(
win.document.getElementById("TabsToolbar")
);
simulateItemDrag(win.document.getElementById("home-button"), navbar, "start");
simulateItemDrag(win.document.getElementById("library-button"), bookmarksBar);
simulateItemDrag(win.document.getElementById("stop-reload-button"), tabBar);
simulateItemDrag(
win.document.getElementById("stop-reload-button"),
navbar,
"start"
);
simulateItemDrag(win.document.getElementById("stop-reload-button"), tabBar);
await leaveCustomizationMode(win);
await BrowserTestUtils.closeWindow(win);
assertCustomizeScalars({
"home-button_move_nav-bar-end_nav-bar-start_drag": 1,
"library-button_move_nav-bar-end_bookmarks-bar_drag": 1,
"stop-reload-button_move_nav-bar-start_tabs-bar_drag": 2,
"stop-reload-button_move_tabs-bar_nav-bar-start_drag": 1,
"bookmarks-bar_move_off_on_customization-toolbar-menu": 1,
});
CustomizableUI.reset();
});
add_task(async function contextMenus() {
// Create a default state.
organizeToolbars({
PersonalToolbar: ["personal-bookmarks"],
TabsToolbar: ["tabbrowser-tabs", "new-tab-button"],
"nav-bar": [
"back-button",
"forward-button",
"stop-reload-button",
"urlbar-container",
"home-button",
"library-button",
],
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"new-tab-button_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"back-button_pinned_nav-bar-start",
"forward-button_pinned_nav-bar-start",
"stop-reload-button_pinned_nav-bar-start",
"home-button_pinned_nav-bar-end",
"library-button_pinned_nav-bar-end",
"personal-bookmarks_pinned_bookmarks-bar",
]);
let menu = document.getElementById("toolbar-context-menu");
let popupShown = BrowserTestUtils.waitForEvent(menu, "popupshown");
let button = document.getElementById("stop-reload-button");
EventUtils.synthesizeMouseAtCenter(
button,
{ type: "contextmenu", button: 2 },
window
);
await popupShown;
let popupHidden = BrowserTestUtils.waitForEvent(menu, "popuphidden");
let barButton = document.getElementById("toggle_PersonalToolbar");
EventUtils.synthesizeMouseAtCenter(barButton, {}, window);
await popupHidden;
popupShown = BrowserTestUtils.waitForEvent(menu, "popupshown");
EventUtils.synthesizeMouseAtCenter(
button,
{ type: "contextmenu", button: 2 },
window
);
await popupShown;
popupHidden = BrowserTestUtils.waitForEvent(menu, "popuphidden");
let removeButton = document.querySelector(
"#toolbar-context-menu .customize-context-removeFromToolbar"
);
EventUtils.synthesizeMouseAtCenter(removeButton, {}, window);
await popupHidden;
assertCustomizeScalars({
"bookmarks-bar_move_off_on_toolbar-context-menu": 1,
"stop-reload-button_remove_nav-bar-start_na_toolbar-context-menu": 1,
});
CustomizableUI.reset();
});
add_task(async function pageActions() {
// The page action button is only visible when a page is loaded.
await BrowserTestUtils.withNewTab("http://example.com", async () => {
// Create a default state.
organizeToolbars({
PersonalToolbar: ["personal-bookmarks"],
TabsToolbar: ["tabbrowser-tabs", "new-tab-button"],
"nav-bar": [
"back-button",
"forward-button",
"stop-reload-button",
"urlbar-container",
"home-button",
"library-button",
],
pageActionsInUrlBar: ["emailLink", "pinTab"],
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"new-tab-button_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"back-button_pinned_nav-bar-start",
"forward-button_pinned_nav-bar-start",
"stop-reload-button_pinned_nav-bar-start",
"home-button_pinned_nav-bar-end",
"library-button_pinned_nav-bar-end",
"emailLink_pinned_pageaction-urlbar",
"pinTab_pinned_pageaction-urlbar",
"personal-bookmarks_pinned_bookmarks-bar",
]);
let panel = document.getElementById("pageActionPanel");
let button = document.getElementById("pageActionButton");
let context = document.getElementById("pageActionContextMenu");
let popupShown = BrowserTestUtils.waitForEvent(panel, "popupshown");
EventUtils.synthesizeMouseAtCenter(button, {}, window);
await popupShown;
popupShown = BrowserTestUtils.waitForEvent(context, "popupshown");
EventUtils.synthesizeMouseAtCenter(
document.getElementById("pageAction-panel-copyURL"),
{ type: "contextmenu", button: 2 },
window
);
await popupShown;
let popupHidden = BrowserTestUtils.waitForEvent(context, "popuphidden");
EventUtils.synthesizeMouseAtCenter(
document.querySelector(".pageActionContextMenuItem.builtInUnpinned"),
{},
window
);
await popupHidden;
popupHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
EventUtils.synthesizeMouseAtCenter(button, {}, window);
await popupHidden;
popupShown = BrowserTestUtils.waitForEvent(context, "popupshown");
EventUtils.synthesizeMouseAtCenter(
document.getElementById("pageAction-urlbar-emailLink"),
{ type: "contextmenu", button: 2 },
window
);
await popupShown;
popupHidden = BrowserTestUtils.waitForEvent(context, "popuphidden");
EventUtils.synthesizeMouseAtCenter(
document.querySelector(".pageActionContextMenuItem.builtInPinned"),
{},
window
);
await popupHidden;
assertCustomizeScalars({
"copyURL_add_na_pageaction-urlbar_pageaction-context": 1,
"emailLink_remove_pageaction-urlbar_na_pageaction-context": 1,
});
CustomizableUI.reset();
});
});
add_task(async function extensions() {
// The page action button is only visible when a page is loaded.
await BrowserTestUtils.withNewTab("http://example.com", async () => {
organizeToolbars();
const extension = ExtensionTestUtils.loadExtension({
useAddonManager: "temporary",
manifest: {
version: "1",
applications: {
gecko: { id: "random_addon@example.com" },
},
browser_action: {
default_icon: "default.png",
default_title: "Hello",
},
page_action: {
default_icon: "default.png",
default_title: "Hello",
},
},
});
await extension.startup();
assertCustomizeScalars({
"random-addon-example-com_add_na_nav-bar-end_addon": 1,
"random-addon-example-com_add_na_pageaction-urlbar_addon": 1,
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
"random-addon-example-com_pinned_nav-bar-end",
"random-addon-example-com_pinned_pageaction-urlbar",
]);
let addon = await AddonManager.getAddonByID(extension.id);
await addon.disable();
assertCustomizeScalars({
"random-addon-example-com_remove_nav-bar-end_na_addon": 1,
"random-addon-example-com_remove_pageaction-urlbar_na_addon": 1,
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
]);
await addon.enable();
assertCustomizeScalars({
"random-addon-example-com_add_na_nav-bar-end_addon": 1,
"random-addon-example-com_add_na_pageaction-urlbar_addon": 1,
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
"random-addon-example-com_pinned_nav-bar-end",
"random-addon-example-com_pinned_pageaction-urlbar",
]);
await addon.reload();
assertCustomizeScalars({});
await enterCustomizationMode();
let navbar = CustomizableUI.getCustomizationTarget(
document.getElementById("nav-bar")
);
simulateItemDrag(
document.getElementById("random_addon_example_com-browser-action"),
navbar,
"start"
);
await leaveCustomizationMode();
assertCustomizeScalars({
"random-addon-example-com_move_nav-bar-end_nav-bar-start_drag": 1,
});
await extension.unload();
assertCustomizeScalars({
"random-addon-example-com_remove_nav-bar-start_na_addon": 1,
"random-addon-example-com_remove_pageaction-urlbar_na_addon": 1,
});
BrowserUsageTelemetry._recordUITelemetry();
assertVisibilityScalars([
"drag-space_pinned_off",
"menu-toolbar_pinned_off",
"titlebar_pinned_off",
"bookmarks-bar_pinned_off",
"tabbrowser-tabs_pinned_tabs-bar",
"alltabs-button_pinned_tabs-bar",
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
]);
});
});

Просмотреть файл

@ -2089,6 +2089,51 @@ var BrowserTestUtils = {
});
},
/**
* Waits for CSS transitions to complete for an element. Tracks any
* transitions that start after this function is called and resolves once all
* started transitions complete.
*
* @param element (Element)
* The element that will transition.
* @param timeout (number)
* The maximum time to wait in milliseconds. Defaults to 5 seconds.
* @return Promise
* Resolves when transitions complete or rejects if the timeout is hit.
*/
waitForTransition(element, timeout = 5000) {
return new Promise((resolve, reject) => {
let cleanup = () => {
element.removeEventListener("transitionrun", listener);
element.removeEventListener("transitionend", listener);
};
let timer = element.ownerGlobal.setTimeout(() => {
cleanup();
reject();
}, timeout);
let transitionCount = 0;
let listener = event => {
if (event.type == "transitionrun") {
transitionCount++;
} else {
transitionCount--;
if (transitionCount == 0) {
cleanup();
element.ownerGlobal.clearTimeout(timer);
resolve();
}
}
};
element.addEventListener("transitionrun", listener);
element.addEventListener("transitionend", listener);
element.addEventListener("transitioncancel", listener);
});
},
_knownAboutPages: new Set(),
_loadedAboutContentScript: false,
/**

Просмотреть файл

@ -561,6 +561,389 @@ browser.input:
- 'main'
- 'content'
browser.ui:
toolbar_widgets:
bug_numbers:
- 1620358
description: >
The widgets in the toolbars.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: boolean
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
customized_widgets:
bug_numbers:
- 1620358
description: >
Records when widgets are added, removed or moved in the UI.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
browser.ui.interaction:
keyboard:
bug_numbers:
- 1620358
description: >
Records a count of interactions with keyboard shortcuts.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
menu_bar:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the menu bar.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
tabs_bar:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the tab bar.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
nav_bar:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the nav bar.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
bookmarks_bar:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the bookmarks bar.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
app_menu:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the app menu.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
tabs_context:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the tab context menu.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
content_context:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the content context menu.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
overflow_menu:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the overflow menu.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
pinned_overflow_menu:
bug_numbers:
- 1620358
description: >
Records a count of interactions with items in the pinned area of the
overflow menu.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
pageaction_urlbar:
bug_numbers:
- 1620358
description: >
Records a count of interactions with page action items in the url bar.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
pageaction_panel:
bug_numbers:
- 1620358
description: >
Records a count of interactions with page action items in the panel.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_paneHome:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the Home section of preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_paneGeneral:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the General section of preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_panePrivacy:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the Privacy section of preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_paneSearch:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the Search section of preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_paneSearchResults:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the Search results section of
preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_paneSync:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the Sync section of preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
preferences_paneContainers:
bug_numbers:
- 1620358
description: >
Records the items interacted with in the Containers section of
preferences.
See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html
expires: never
kind: uint
keyed: true
notification_emails:
- shong@mozilla.com
- dtownsend@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- 'main'
gecko:
version:
bug_numbers: