DefaultBrowserCheck.sys.mjs (7527B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; 6 7 let lazy = {}; 8 ChromeUtils.defineESModuleGetters(lazy, { 9 BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs", 10 CommonDialog: "resource://gre/modules/CommonDialog.sys.mjs", 11 SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", 12 }); 13 14 export var DefaultBrowserCheck = { 15 async prompt(win) { 16 const shellService = win.getShellService(); 17 const needPin = 18 (await shellService.doesAppNeedPin()) || 19 (await shellService.doesAppNeedStartMenuPin()); 20 21 win.MozXULElement.insertFTLIfNeeded("branding/brand.ftl"); 22 win.MozXULElement.insertFTLIfNeeded( 23 "browser/defaultBrowserNotification.ftl" 24 ); 25 // Record default prompt impression 26 let now = Math.floor(Date.now() / 1000).toString(); 27 Services.prefs.setCharPref( 28 "browser.shell.mostRecentDefaultPromptSeen", 29 now 30 ); 31 32 // Resolve the translations for the prompt elements and return only the 33 // string values 34 35 let pinMessage; 36 if (AppConstants.platform == "macosx") { 37 pinMessage = "default-browser-prompt-message-pin-mac"; 38 } else if ( 39 AppConstants.platform == "win" && 40 Services.sysinfo.getProperty("hasWinPackageId", false) 41 ) { 42 pinMessage = "default-browser-prompt-message-pin-msix"; 43 } else { 44 pinMessage = "default-browser-prompt-message-pin"; 45 } 46 let [promptTitle, promptMessage, askLabel, yesButton, notNowButton] = ( 47 await win.document.l10n.formatMessages([ 48 { 49 id: needPin 50 ? "default-browser-prompt-title-pin" 51 : "default-browser-prompt-title-alt", 52 }, 53 { 54 id: needPin ? pinMessage : "default-browser-prompt-message-alt", 55 }, 56 { id: "default-browser-prompt-checkbox-not-again-label" }, 57 { 58 id: needPin 59 ? "default-browser-prompt-button-primary-set" 60 : "default-browser-prompt-button-primary-alt", 61 }, 62 { id: "default-browser-prompt-button-secondary" }, 63 ]) 64 ).map(({ value }) => value); 65 66 let ps = Services.prompt; 67 let buttonFlags = 68 ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 + 69 ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_1 + 70 ps.BUTTON_POS_0_DEFAULT; 71 let rv = await ps.asyncConfirmEx( 72 win.browsingContext, 73 ps.MODAL_TYPE_INTERNAL_WINDOW, 74 promptTitle, 75 promptMessage, 76 buttonFlags, 77 yesButton, 78 notNowButton, 79 null, 80 askLabel, 81 false, // checkbox state 82 { 83 headerIconCSSValue: lazy.CommonDialog.DEFAULT_APP_ICON_CSS, 84 } 85 ); 86 let buttonNumClicked = rv.get("buttonNumClicked"); 87 let checkboxState = rv.get("checked"); 88 if (buttonNumClicked == 0) { 89 // We must explicitly await pinning to the taskbar before 90 // trying to set as default. If we fall back to setting 91 // as default through the Windows Settings menu that interferes 92 // with showing the pinning notification as we no longer have 93 // window focus. 94 try { 95 await shellService.pinToTaskbar(); 96 } catch (e) { 97 this.log.error("Failed to pin to taskbar", e); 98 } 99 try { 100 await shellService.pinToStartMenu(); 101 } catch (e) { 102 this.log.error("Failed to pin to Start Menu", e); 103 } 104 try { 105 await shellService.setAsDefault(); 106 } catch (e) { 107 this.log.error("Failed to set the default browser", e); 108 } 109 } 110 if (checkboxState) { 111 shellService.shouldCheckDefaultBrowser = false; 112 Services.prefs.setCharPref("browser.shell.userDisabledDefaultCheck", now); 113 } 114 115 try { 116 let resultEnum = buttonNumClicked * 2 + !checkboxState; 117 Glean.browser.setDefaultResult.accumulateSingleSample(resultEnum); 118 } catch (ex) { 119 /* Don't break if Telemetry is acting up. */ 120 } 121 }, 122 123 /** 124 * Checks if the default browser check prompt will be shown. 125 * 126 * @param {boolean} isStartupCheck 127 * If true, prefs will be set and telemetry will be recorded. 128 * @returns {boolean} True if the default browser check prompt will be shown. 129 */ 130 async willCheckDefaultBrowser(isStartupCheck) { 131 let win = lazy.BrowserWindowTracker.getTopWindow({ 132 allowFromInactiveWorkspace: true, 133 }); 134 let shellService = win.getShellService(); 135 136 // Perform default browser checking. 137 if (!shellService) { 138 return false; 139 } 140 141 let shouldCheck = 142 !AppConstants.DEBUG && shellService.shouldCheckDefaultBrowser; 143 144 // Even if we shouldn't check the default browser, we still continue when 145 // isStartupCheck = true to set prefs and telemetry. 146 if (!shouldCheck && !isStartupCheck) { 147 return false; 148 } 149 150 // Skip the "Set Default Browser" check during first-run or after the 151 // browser has been run a few times. 152 const skipDefaultBrowserCheck = 153 Services.prefs.getBoolPref( 154 "browser.shell.skipDefaultBrowserCheckOnFirstRun" 155 ) && 156 !Services.prefs.getBoolPref( 157 "browser.shell.didSkipDefaultBrowserCheckOnFirstRun" 158 ); 159 160 let promptCount = Services.prefs.getIntPref( 161 "browser.shell.defaultBrowserCheckCount", 162 0 163 ); 164 165 // If SessionStartup's state is not initialized, checking sessionType will set 166 // its internal state to "do not restore". 167 await lazy.SessionStartup.onceInitialized; 168 let willRecoverSession = 169 lazy.SessionStartup.sessionType == lazy.SessionStartup.RECOVER_SESSION; 170 171 // Don't show the prompt if we're already the default browser. 172 let isDefault = false; 173 let isDefaultError = false; 174 try { 175 isDefault = shellService.isDefaultBrowser(isStartupCheck, false); 176 } catch (ex) { 177 isDefaultError = true; 178 } 179 180 if (isDefault && isStartupCheck) { 181 let now = Math.floor(Date.now() / 1000).toString(); 182 Services.prefs.setCharPref( 183 "browser.shell.mostRecentDateSetAsDefault", 184 now 185 ); 186 } 187 188 let willPrompt = shouldCheck && !isDefault && !willRecoverSession; 189 190 if (willPrompt) { 191 if (skipDefaultBrowserCheck) { 192 if (isStartupCheck) { 193 Services.prefs.setBoolPref( 194 "browser.shell.didSkipDefaultBrowserCheckOnFirstRun", 195 true 196 ); 197 } 198 willPrompt = false; 199 } else { 200 promptCount++; 201 if (isStartupCheck) { 202 Services.prefs.setIntPref( 203 "browser.shell.defaultBrowserCheckCount", 204 promptCount 205 ); 206 } 207 if (!AppConstants.RELEASE_OR_BETA && promptCount > 3) { 208 willPrompt = false; 209 } 210 } 211 } 212 213 if (isStartupCheck) { 214 try { 215 // Report default browser status on startup to telemetry 216 // so we can track whether we are the default. 217 Glean.browser.isUserDefault[isDefault ? "true" : "false"].add(); 218 Glean.browser.isUserDefaultError[ 219 isDefaultError ? "true" : "false" 220 ].add(); 221 Glean.browser.setDefaultAlwaysCheck[ 222 shouldCheck ? "true" : "false" 223 ].add(); 224 Glean.browser.setDefaultDialogPromptRawcount.accumulateSingleSample( 225 promptCount 226 ); 227 } catch (ex) { 228 /* Don't break the default prompt if telemetry is broken. */ 229 } 230 } 231 232 return willPrompt; 233 }, 234 };