Bug 1712306 - add telemetry for the close multiple tabs modal, r=jaws

Differential Revision: https://phabricator.services.mozilla.com/D115840
This commit is contained in:
Gijs Kruitbosch 2021-05-27 21:01:01 +00:00
parent c329fa104b
commit 1d7f4797cd
7 changed files with 155 additions and 22 deletions

View File

@ -33,11 +33,11 @@
<command id="cmd_file_importFromAnotherBrowser" oncommand="MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_FILE_MENU]);"/>
<command id="cmd_help_importFromAnotherBrowser" oncommand="MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_HELP_MENU]);"/>
<command id="cmd_close" oncommand="BrowserCloseTabOrWindow(event);"/>
<command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/>
<command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow(event)"/>
<command id="cmd_toggleMute" oncommand="gBrowser.toggleMuteAudioOnMultiSelectedTabs(gBrowser.selectedTab)"/>
<command id="cmd_CustomizeToolbars" oncommand="gCustomizeMode.enter()"/>
<command id="cmd_toggleOfflineStatus" oncommand="BrowserOffline.toggleOfflineStatus();"/>
<command id="cmd_quitApplication" oncommand="goQuitApplication()"/>
<command id="cmd_quitApplication" oncommand="goQuitApplication(event)"/>
<command id="View:PageSource" oncommand="BrowserViewSource(window.gBrowser.selectedBrowser);"/>
<command id="View:PageInfo" oncommand="BrowserPageInfo();"/>

View File

@ -3043,8 +3043,8 @@ function BrowserCloseTabOrWindow(event) {
gBrowser.removeCurrentTab({ animate: true });
}
function BrowserTryToCloseWindow() {
if (WindowIsClosing()) {
function BrowserTryToCloseWindow(event) {
if (WindowIsClosing(event)) {
window.close();
} // WindowIsClosing does all the necessary checks
}
@ -7860,8 +7860,20 @@ function CanCloseWindow() {
return true;
}
function WindowIsClosing() {
if (!closeWindow(false, warnAboutClosingWindow)) {
function WindowIsClosing(event) {
let source;
if (event) {
let target = event.sourceEvent?.target;
if (target?.id?.startsWith("menu_")) {
source = "menuitem";
} else if (target?.nodeName == "toolbarbutton") {
source = "close-button";
} else {
let key = AppConstants.platform == "macosx" ? "metaKey" : "ctrlKey";
source = event[key] ? "shortcut" : "OS";
}
}
if (!closeWindow(false, warnAboutClosingWindow, source)) {
return false;
}
@ -7883,9 +7895,11 @@ function WindowIsClosing() {
/**
* Checks if this is the last full *browser* window around. If it is, this will
* be communicated like quitting. Otherwise, we warn about closing multiple tabs.
*
* @param source where the request to close came from (used for telemetry)
* @returns true if closing can proceed, false if it got cancelled.
*/
function warnAboutClosingWindow() {
function warnAboutClosingWindow(source) {
// Popups aren't considered full browser windows; we also ignore private windows.
let isPBWindow =
PrivateBrowsingUtils.isWindowPrivate(window) &&
@ -7896,7 +7910,8 @@ function warnAboutClosingWindow() {
if (!isPBWindow && !toolbar.visible) {
return gBrowser.warnAboutClosingTabs(
closingTabs,
gBrowser.closingTabsEnum.ALL
gBrowser.closingTabsEnum.ALL,
source
);
}
@ -7934,7 +7949,11 @@ function warnAboutClosingWindow() {
if (otherWindowExists) {
return (
isPBWindow ||
gBrowser.warnAboutClosingTabs(closingTabs, gBrowser.closingTabsEnum.ALL)
gBrowser.warnAboutClosingTabs(
closingTabs,
gBrowser.closingTabsEnum.ALL,
source
)
);
}
@ -7956,7 +7975,11 @@ function warnAboutClosingWindow() {
return (
AppConstants.platform != "macosx" ||
isPBWindow ||
gBrowser.warnAboutClosingTabs(closingTabs, gBrowser.closingTabsEnum.ALL)
gBrowser.warnAboutClosingTabs(
closingTabs,
gBrowser.closingTabsEnum.ALL,
source
)
);
}

View File

@ -2124,7 +2124,7 @@
<toolbarbutton id="close-button"
data-l10n-id="browser-window-close-button"
oncommand="BrowserTryToCloseWindow();"/>
oncommand="BrowserTryToCloseWindow(event);"/>
</hbox>
</toolbar>

View File

@ -3108,7 +3108,7 @@
}
},
warnAboutClosingTabs(tabsToClose, aCloseTabs) {
warnAboutClosingTabs(tabsToClose, aCloseTabs, aSource) {
if (tabsToClose <= 1) {
return true;
}
@ -3171,6 +3171,40 @@
checkboxLabel,
warnOnClose
);
Services.telemetry.setEventRecordingEnabled("close_tab_warning", true);
let closeTabEnumKey =
Object.entries(this.closingTabsEnum)
.find(([k, v]) => v == aCloseTabs)?.[0]
?.toLowerCase() || "some";
let warnCheckbox = warnOnClose.value ? "checked" : "unchecked";
if (!checkboxLabel) {
warnCheckbox = "not-present";
}
let sessionWillBeRestored =
Services.prefs.getIntPref("browser.startup.page") == 3 ||
Services.prefs.getBoolPref("browser.sessionstore.resume_session_once");
let closesWindow = aCloseTabs == this.closingTabsEnum.ALL;
Services.telemetry.recordEvent(
"close_tab_warning",
"shown",
closesWindow ? "window" : "tabs",
null,
{
source: aSource || `close-${closeTabEnumKey}-tabs`,
button: buttonPressed == 0 ? "close" : "cancel",
warn_checkbox: warnCheckbox,
closing_tabs: "" + tabsToClose,
closing_wins: "" + +closesWindow, // ("1" or "0", depending on the value)
// This value doesn't really apply to whether this warning
// gets shown, but having pings be consistent (and perhaps
// being able to see trends for users with/without sessionrestore)
// seems useful:
will_restore: sessionWillBeRestored ? "yes" : "no",
}
);
var reallyClose = buttonPressed == 0;
// don't set the pref unless they press OK and it's false
@ -3399,7 +3433,8 @@
) {
window.closeWindow(
true,
suppressWarnAboutClosingWindow ? null : window.warnAboutClosingWindow
suppressWarnAboutClosingWindow ? null : window.warnAboutClosingWindow,
"close-last-tab"
);
return;
}
@ -3725,7 +3760,8 @@
// cancels the operation. We are finished here in both cases.
this._windowIsClosing = window.closeWindow(
true,
window.warnAboutClosingWindow
window.warnAboutClosingWindow,
"close-last-tab"
);
return false;
}
@ -3991,7 +4027,8 @@
if (aCloseWindow) {
this._windowIsClosing = closeWindow(
true,
window.warnAboutClosingWindow
window.warnAboutClosingWindow,
"close-last-tab"
);
}
},

View File

@ -2694,6 +2694,11 @@ BrowserGlue.prototype = {
);
},
_quitSource: "unknown",
_registerQuitSource(source) {
this._quitSource = source;
},
_onQuitRequest: function BG__onQuitRequest(aCancelQuit, aQuitType) {
// If user has already dismissed quit request, then do nothing
if (aCancelQuit instanceof Ci.nsISupportsPRBool && aCancelQuit.data) {
@ -2722,6 +2727,7 @@ BrowserGlue.prototype = {
var windowcount = 0;
var pagecount = 0;
let pinnedcount = 0;
for (let win of BrowserWindowTracker.orderedWindows) {
if (win.closed) {
continue;
@ -2729,6 +2735,7 @@ BrowserGlue.prototype = {
windowcount++;
let tabbrowser = win.gBrowser;
if (tabbrowser) {
pinnedcount += tabbrowser._numPinnedTabs;
pagecount +=
tabbrowser.browsers.length -
tabbrowser._numPinnedTabs -
@ -2826,6 +2833,28 @@ BrowserGlue.prototype = {
checkboxLabel,
warnOnClose
);
Services.telemetry.setEventRecordingEnabled("close_tab_warning", true);
let warnCheckbox = warnOnClose.value ? "checked" : "unchecked";
if (!checkboxLabel) {
warnCheckbox = "not-present";
}
Services.telemetry.recordEvent(
"close_tab_warning",
"shown",
"application",
null,
{
source: this._quitSource,
button: buttonPressed == 0 ? "close" : "cancel",
warn_checkbox: warnCheckbox,
closing_wins: "" + windowcount,
closing_tabs: "" + (pagecount + pinnedcount),
will_restore: sessionWillBeRestored ? "yes" : "no",
}
);
this._quitSource = "unknown";
// If the user has unticked the box, and has confirmed closing, stop showing
// the warning.
if (!sessionWillBeRestored && buttonPressed == 0 && !warnOnClose.value) {

View File

@ -2896,3 +2896,25 @@ contextservices.quicksuggest:
notification_emails:
- fx-search@mozilla.com
expiry_version: never
close_tab_warning:
shown:
description: >
Recorded whenever we show the 'Close Tabs' dialog, with details about
the reason it is shown and what choices the user makes (close or not).
objects: ["window", "application", "tabs"]
release_channel_collection: opt-out
expiry_version: "94"
record_in_processes: ["main"]
products: ["firefox"]
bug_numbers: [1712306]
notification_emails:
- gkruitbosch@mozilla.com
- rtestard@mozilla.com
extra_keys:
source: The way in which the tabs were closed (shortcut, close button, menuitem, appmenu, etc.)
button: Which button the user clicked (Close tabs or Cancel)
warn_checkbox: Whether the checkbox to display the warning again was checked or not.
closing_wins: The number of windows being closed.
closing_tabs: The number of tabs being closed.
will_restore: Whether the session will be restored if closed now.

View File

@ -2,7 +2,7 @@
* 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/. */
function closeWindow(aClose, aPromptFunction) {
function closeWindow(aClose, aPromptFunction, aSource) {
let { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
@ -20,17 +20,20 @@ function closeWindow(aClose, aPromptFunction) {
}
// If we're down to the last window and someone tries to shut down, check to make sure we can!
if (windowCount == 1 && !canQuitApplication("lastwindow")) {
if (windowCount == 1 && !canQuitApplication("lastwindow", aSource)) {
return false;
}
if (
windowCount != 1 &&
typeof aPromptFunction == "function" &&
!aPromptFunction()
!aPromptFunction(aSource)
) {
return false;
}
} else if (typeof aPromptFunction == "function" && !aPromptFunction()) {
} else if (
typeof aPromptFunction == "function" &&
!aPromptFunction(aSource)
) {
return false;
}
@ -42,7 +45,12 @@ function closeWindow(aClose, aPromptFunction) {
return true;
}
function canQuitApplication(aData) {
function canQuitApplication(aData, aSource) {
const kCID = "@mozilla.org/browser/browserglue;1";
if (kCID in Cc && !(aData || "").includes("restart")) {
let BrowserGlue = Cc[kCID].getService(Ci.nsISupports).wrappedJSObject;
BrowserGlue._registerQuitSource(aSource);
}
try {
var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
Ci.nsISupportsPRBool
@ -61,8 +69,22 @@ function canQuitApplication(aData) {
return true;
}
function goQuitApplication() {
if (!canQuitApplication()) {
function goQuitApplication(event) {
// We can't know for sure if the user used a shortcut to trigger quit.
// Proxy by means of checking for the shortcut modifier.
let isMac = navigator.platform.startsWith("Mac");
let key = isMac ? "metaKey" : "ctrlKey";
let source = "OS";
if (event[key]) {
source = "shortcut";
// Note that macOS likes pretending something came from this menu even if
// activated by keyboard shortcut, hence checking that first.
} else if (event.sourceEvent?.target?.id?.startsWith("menu_")) {
source = "menuitem";
} else if (event.sourceEvent?.target?.id?.startsWith("appMenu")) {
source = "appmenu";
}
if (!canQuitApplication(undefined, source)) {
return false;
}