/* 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/. */ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; let lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs", CommonDialog: "resource://gre/modules/CommonDialog.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", }); export var DefaultBrowserCheck = { async prompt(win) { const shellService = win.getShellService(); const needPin = (await shellService.doesAppNeedPin()) || (await shellService.doesAppNeedStartMenuPin()); win.MozXULElement.insertFTLIfNeeded("branding/brand.ftl"); win.MozXULElement.insertFTLIfNeeded( "browser/defaultBrowserNotification.ftl" ); // Record default prompt impression let now = Math.floor(Date.now() / 1000).toString(); Services.prefs.setCharPref( "browser.shell.mostRecentDefaultPromptSeen", now ); // Resolve the translations for the prompt elements and return only the // string values let pinMessage; if (AppConstants.platform == "macosx") { pinMessage = "default-browser-prompt-message-pin-mac"; } else if ( AppConstants.platform == "win" && Services.sysinfo.getProperty("hasWinPackageId", false) ) { pinMessage = "default-browser-prompt-message-pin-msix"; } else { pinMessage = "default-browser-prompt-message-pin"; } let [promptTitle, promptMessage, askLabel, yesButton, notNowButton] = ( await win.document.l10n.formatMessages([ { id: needPin ? "default-browser-prompt-title-pin" : "default-browser-prompt-title-alt", }, { id: needPin ? pinMessage : "default-browser-prompt-message-alt", }, { id: "default-browser-prompt-checkbox-not-again-label" }, { id: needPin ? "default-browser-prompt-button-primary-set" : "default-browser-prompt-button-primary-alt", }, { id: "default-browser-prompt-button-secondary" }, ]) ).map(({ value }) => value); let ps = Services.prompt; let buttonFlags = ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 + ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_1 + ps.BUTTON_POS_0_DEFAULT; let rv = await ps.asyncConfirmEx( win.browsingContext, ps.MODAL_TYPE_INTERNAL_WINDOW, promptTitle, promptMessage, buttonFlags, yesButton, notNowButton, null, askLabel, false, // checkbox state { headerIconCSSValue: lazy.CommonDialog.DEFAULT_APP_ICON_CSS, } ); let buttonNumClicked = rv.get("buttonNumClicked"); let checkboxState = rv.get("checked"); if (buttonNumClicked == 0) { // We must explicitly await pinning to the taskbar before // trying to set as default. If we fall back to setting // as default through the Windows Settings menu that interferes // with showing the pinning notification as we no longer have // window focus. try { await shellService.pinToTaskbar(); } catch (e) { this.log.error("Failed to pin to taskbar", e); } try { await shellService.pinToStartMenu(); } catch (e) { this.log.error("Failed to pin to Start Menu", e); } try { await shellService.setAsDefault(); } catch (e) { this.log.error("Failed to set the default browser", e); } } if (checkboxState) { shellService.shouldCheckDefaultBrowser = false; Services.prefs.setCharPref("browser.shell.userDisabledDefaultCheck", now); } try { let resultEnum = buttonNumClicked * 2 + !checkboxState; Glean.browser.setDefaultResult.accumulateSingleSample(resultEnum); } catch (ex) { /* Don't break if Telemetry is acting up. */ } }, /** * Checks if the default browser check prompt will be shown. * * @param {boolean} isStartupCheck * If true, prefs will be set and telemetry will be recorded. * @returns {boolean} True if the default browser check prompt will be shown. */ async willCheckDefaultBrowser(isStartupCheck) { let win = lazy.BrowserWindowTracker.getTopWindow(); let shellService = win.getShellService(); // Perform default browser checking. if (!shellService) { return false; } let shouldCheck = !AppConstants.DEBUG && shellService.shouldCheckDefaultBrowser; // Even if we shouldn't check the default browser, we still continue when // isStartupCheck = true to set prefs and telemetry. if (!shouldCheck && !isStartupCheck) { return false; } // Skip the "Set Default Browser" check during first-run or after the // browser has been run a few times. const skipDefaultBrowserCheck = Services.prefs.getBoolPref( "browser.shell.skipDefaultBrowserCheckOnFirstRun" ) && !Services.prefs.getBoolPref( "browser.shell.didSkipDefaultBrowserCheckOnFirstRun" ); let promptCount = Services.prefs.getIntPref( "browser.shell.defaultBrowserCheckCount", 0 ); // If SessionStartup's state is not initialized, checking sessionType will set // its internal state to "do not restore". await lazy.SessionStartup.onceInitialized; let willRecoverSession = lazy.SessionStartup.sessionType == lazy.SessionStartup.RECOVER_SESSION; // Don't show the prompt if we're already the default browser. let isDefault = false; let isDefaultError = false; try { isDefault = shellService.isDefaultBrowser(isStartupCheck, false); } catch (ex) { isDefaultError = true; } if (isDefault && isStartupCheck) { let now = Math.floor(Date.now() / 1000).toString(); Services.prefs.setCharPref( "browser.shell.mostRecentDateSetAsDefault", now ); } let willPrompt = shouldCheck && !isDefault && !willRecoverSession; if (willPrompt) { if (skipDefaultBrowserCheck) { if (isStartupCheck) { Services.prefs.setBoolPref( "browser.shell.didSkipDefaultBrowserCheckOnFirstRun", true ); } willPrompt = false; } else { promptCount++; if (isStartupCheck) { Services.prefs.setIntPref( "browser.shell.defaultBrowserCheckCount", promptCount ); } if (!AppConstants.RELEASE_OR_BETA && promptCount > 3) { willPrompt = false; } } } if (isStartupCheck) { try { // Report default browser status on startup to telemetry // so we can track whether we are the default. Glean.browser.isUserDefault[isDefault ? "true" : "false"].add(); Glean.browser.isUserDefaultError[ isDefaultError ? "true" : "false" ].add(); Glean.browser.setDefaultAlwaysCheck[ shouldCheck ? "true" : "false" ].add(); Glean.browser.setDefaultDialogPromptRawcount.accumulateSingleSample( promptCount ); } catch (ex) { /* Don't break the default prompt if telemetry is broken. */ } } return willPrompt; }, };