author | Ed Lee <edilee@mozilla.com> |
Tue, 13 Apr 2021 00:04:30 +0000 | |
changeset 575568 | 6c72185b0f4445be2da32a2ce523ad9fc32a7587 |
parent 575567 | 4d8df052a78060bd54db95d355d235f786f1f6d5 |
child 575569 | 7388f5dc0e03eca6bba358ef97c2c0764fe8520a |
push id | 38367 |
push user | abutkovits@mozilla.com |
push date | Tue, 13 Apr 2021 03:56:47 +0000 |
treeherder | mozilla-central@d68cc4d521d9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | andreio |
bugs | 1697222 |
milestone | 89.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -296,16 +296,19 @@ pref("browser.startup.firstrunSkipsHomep #if defined(XP_WIN) #ifdef NIGHTLY_BUILD pref("browser.startup.preXulSkeletonUI", true); #else pref("browser.startup.preXulSkeletonUI", false); #endif #endif +// Show an upgrade dialog on major upgrades. +pref("browser.startup.upgradeDialog.enabled", true); + // Don't create the hidden window during startup on // platforms that don't always need it (Win/Linux). pref("toolkit.lazyHiddenWindow", true); pref("browser.chrome.site_icons", true); // browser.warnOnQuit == false will override all other possible prompts when quitting or restarting pref("browser.warnOnQuit", true);
--- a/browser/components/BrowserContentHandler.jsm +++ b/browser/components/BrowserContentHandler.jsm @@ -87,17 +87,17 @@ function resolveURIInternal(aCmdLine, aA } catch (e) { Cu.reportError(e); } return uri; } let gKiosk = false; - +let gMajorUpgrade = false; var gFirstWindow = false; const OVERRIDE_NONE = 0; const OVERRIDE_NEW_PROFILE = 1; const OVERRIDE_NEW_MSTONE = 2; const OVERRIDE_NEW_BUILD_ID = 3; const OVERRIDE_ALTERNATE_PROFILE = 4; /** @@ -137,16 +137,19 @@ function needHomepageOverride(prefb) { if (mstone != savedmstone) { // Bug 462254. Previous releases had a default pref to suppress the EULA // agreement if the platform's installer had already shown one. Now with // about:rights we've removed the EULA stuff and default pref, but we need // a way to make existing profiles retain the default that we removed. if (savedmstone) { prefb.setBoolPref("browser.rights.3.shown", true); + + // Remember that we saw a major version change. + gMajorUpgrade = true; } prefb.setCharPref("browser.startup.homepage_override.mstone", mstone); prefb.setCharPref("browser.startup.homepage_override.buildID", buildID); return savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE; } if (buildID != savedBuildID) { @@ -832,16 +835,24 @@ nsBrowserContentHandler.prototype = { return this.mFeatures; }, get kiosk() { return gKiosk; }, + get majorUpgrade() { + return gMajorUpgrade; + }, + + set majorUpgrade(val) { + gMajorUpgrade = val; + }, + /* nsIContentHandler */ handleContent: function bch_handleContent(contentType, context, request) { const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; try { var webNavInfo = Cc["@mozilla.org/webnavigation-info;1"].getService( Ci.nsIWebNavigationInfo
--- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -50,16 +50,17 @@ XPCOMUtils.defineLazyModuleGetters(this, FirefoxMonitor: "resource:///modules/FirefoxMonitor.jsm", FxAccounts: "resource://gre/modules/FxAccounts.jsm", HomePage: "resource:///modules/HomePage.jsm", Integration: "resource://gre/modules/Integration.jsm", Log: "resource://gre/modules/Log.jsm", LoginBreaches: "resource:///modules/LoginBreaches.jsm", NetUtil: "resource://gre/modules/NetUtil.jsm", NewTabUtils: "resource://gre/modules/NewTabUtils.jsm", + NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm", Normandy: "resource://normandy/Normandy.jsm", OS: "resource://gre/modules/osfile.jsm", OsEnvironment: "resource://gre/modules/OsEnvironment.jsm", PageActions: "resource:///modules/PageActions.jsm", PageThumbs: "resource://gre/modules/PageThumbs.jsm", PdfJs: "resource://pdf.js/PdfJs.jsm", PermissionUI: "resource:///modules/PermissionUI.jsm", PlacesBackups: "resource://gre/modules/PlacesBackups.jsm", @@ -108,22 +109,20 @@ let initializedModules = {}; ].forEach(([name, resource, init]) => { XPCOMUtils.defineLazyGetter(this, name, () => { ChromeUtils.import(resource, initializedModules); initializedModules[name][init](); return initializedModules[name]; }); }); -XPCOMUtils.defineLazyServiceGetter( - this, - "PushService", - "@mozilla.org/push/Service;1", - "nsIPushService" -); +XPCOMUtils.defineLazyServiceGetters(this, { + BrowserHandler: ["@mozilla.org/browser/clh;1", "nsIBrowserHandler"], + PushService: ["@mozilla.org/push/Service;1", "nsIPushService"], +}); const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; /** * Fission-compatible JSProcess implementations. * Each actor options object takes the form of a ProcessActorOptions dictionary. * Detailed documentation of these options is in dom/docs/ipc/jsactors.rst, * available at https://firefox-source-docs.mozilla.org/dom/ipc/jsactors.html @@ -3755,51 +3754,94 @@ BrowserGlue.prototype = { }, _showUpgradeDialog() { BrowserWindowTracker.getTopWindow().gDialogBox.open( "chrome://browser/content/upgradeDialog.html" ); }, - _maybeShowDefaultBrowserPrompt() { - Promise.all([ - DefaultBrowserCheck.willCheckDefaultBrowser(/* isStartupCheck */ true), - ExperimentAPI.ready, - ]).then(async ([willPrompt]) => { - let { DefaultBrowserNotification } = ChromeUtils.import( - "resource:///actors/AboutNewTabParent.jsm", - {} - ); - let isFeatureEnabled = ExperimentAPI.getExperiment({ - featureId: "infobar", - })?.branch.feature.enabled; - if (willPrompt) { - // Prevent the related notification from appearing and - // show the modal prompt. - DefaultBrowserNotification.notifyModalDisplayed(); + async _maybeShowDefaultBrowserPrompt() { + // Highest priority is the upgrade dialog, which can include a "primary + // browser" request and is limited in various ways, e.g., major upgrades. + const dialogVersion = 89; + const dialogVersionPref = "browser.startup.upgradeDialog.version"; + const dialogReason = await (async () => { + if (!Services.prefs.getBoolPref("browser.proton.enabled", true)) { + return "no-proton"; + } + if (!BrowserHandler.majorUpgrade) { + return "not-major"; + } + const lastVersion = Services.prefs.getIntPref(dialogVersionPref, 0); + if (lastVersion > dialogVersion) { + return "newer-shown"; + } + if (lastVersion === dialogVersion) { + return "already-shown"; + } + if ( + !Services.prefs.getBoolPref( + "browser.messaging-system.whatsNewPanel.enabled", + true + ) + ) { + return "no-whatsNew"; + } + if (!Services.prefs.getBoolPref("browser.aboutwelcome.enabled", true)) { + return "no-welcome"; + } + if (!Services.policies.isAllowed("postUpdateCustomPage")) { + return "disallow-postUpdate"; } - // If no experiment go ahead with default experience - if (willPrompt && !isFeatureEnabled) { - let win = BrowserWindowTracker.getTopWindow(); - DefaultBrowserCheck.prompt(win); - } - // If in experiment notify ASRouter to dispatch message - if (isFeatureEnabled) { - ASRouter.waitForInitialized.then(() => - ASRouter.sendTriggerMessage({ - browser: BrowserWindowTracker.getTopWindow()?.gBrowser - .selectedBrowser, - // triggerId and triggerContext - id: "defaultBrowserCheck", - context: { willShowDefaultPrompt: willPrompt }, - }) - ); - } - }); + + // Check enabled last to avoid waiting on remote data in the common case. + await NimbusFeatures.upgradeDialog.ready(); + return NimbusFeatures.upgradeDialog.isEnabled() ? "" : "disabled"; + })(); + + // Show the upgrade dialog if allowed and remember the version. + if (!dialogReason) { + Services.prefs.setIntPref(dialogVersionPref, dialogVersion); + this._showUpgradeDialog(); + return; + } + + // Determine if the modal prompt or infobar message should be shown. + const [willPrompt] = await Promise.all([ + DefaultBrowserCheck.willCheckDefaultBrowser(/* isStartupCheck */ true), + ExperimentAPI.ready(), + ]); + let { DefaultBrowserNotification } = ChromeUtils.import( + "resource:///actors/AboutNewTabParent.jsm", + {} + ); + let isFeatureEnabled = ExperimentAPI.getExperiment({ + featureId: "infobar", + })?.branch.feature.enabled; + if (willPrompt) { + // Prevent the related notification from appearing and + // show the modal prompt. + DefaultBrowserNotification.notifyModalDisplayed(); + } + // If no experiment go ahead with default experience + if (willPrompt && !isFeatureEnabled) { + let win = BrowserWindowTracker.getTopWindow(); + DefaultBrowserCheck.prompt(win); + } + // If in experiment notify ASRouter to dispatch message + if (isFeatureEnabled) { + await ASRouter.waitForInitialized; + ASRouter.sendTriggerMessage({ + browser: BrowserWindowTracker.getTopWindow()?.gBrowser.selectedBrowser, + // triggerId and triggerContext + id: "defaultBrowserCheck", + context: { willShowDefaultPrompt: willPrompt }, + }); + } }, /** * Open preferences even if there are no open windows. */ _openPreferences(...args) { let chromeWindow = BrowserWindowTracker.getTopWindow(); if (chromeWindow) {
--- a/browser/components/nsIBrowserHandler.idl +++ b/browser/components/nsIBrowserHandler.idl @@ -7,15 +7,16 @@ interface nsICommandLine; [scriptable, uuid(8D3F5A9D-118D-4548-A137-CF7718679069)] interface nsIBrowserHandler : nsISupports { attribute AUTF8String startPage; attribute AUTF8String defaultArgs; attribute boolean kiosk; + attribute boolean majorUpgrade; /** * Extract the width and height specified on the command line, if present. * @return A feature string with a prepended comma, e.g. ",width=500,height=400" */ AUTF8String getFeatures(in nsICommandLine aCmdLine); };
--- a/browser/components/tests/browser/browser_browserGlue_upgradeDialog.js +++ b/browser/components/tests/browser/browser_browserGlue_upgradeDialog.js @@ -208,11 +208,47 @@ add_task(async function exit_early() { Assert.equal( mock.setAsDefault.callCount, 0, "Only 1 screen to skip when default" ); }); +add_task(async function not_major_upgrade() { + await BROWSER_GLUE._maybeShowDefaultBrowserPrompt(); +}); + +add_task(async function remote_disabled() { + // TODO(bug 1701948): Set up actual remote defaults. + NimbusFeatures.upgradeDialog._onRemoteReady(); + Services.prefs.setBoolPref("browser.startup.upgradeDialog.enabled", false); + + // Simulate starting from a previous version. + await SpecialPowers.pushPrefEnv({ + set: [["browser.startup.homepage_override.mstone", "88.0"]], + }); + Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs; + + await BROWSER_GLUE._maybeShowDefaultBrowserPrompt(); + + Services.prefs.clearUserPref("browser.startup.upgradeDialog.enabled"); +}); + +add_task(async function show_major_upgrade() { + const promise = waitForDialog(); + await BROWSER_GLUE._maybeShowDefaultBrowserPrompt(); + await promise; + + Assert.ok(true, "Upgrade dialog opened and closed from major upgrade"); +}); + +add_task(async function dont_reshow() { + await BROWSER_GLUE._maybeShowDefaultBrowserPrompt(); +}); + registerCleanupFunction(() => { getShellService.restore(); + Cc["@mozilla.org/browser/clh;1"].getService( + Ci.nsIBrowserHandler + ).majorUpgrade = false; + Services.prefs.clearUserPref("browser.startup.upgradeDialog.version"); });
--- a/browser/components/tests/browser/whats_new_page/browser.ini +++ b/browser/components/tests/browser/whats_new_page/browser.ini @@ -3,10 +3,11 @@ skip-if = verify reason = This is a startup test. Verify runs tests multiple times after startup. support-files = active-update.xml updates/0/update.status prefs = app.update.altUpdateDirPath='<test-root>/browser/components/tests/browser/whats_new_page' app.update.disabledForTesting=false browser.startup.homepage_override.mstone="60.0" + browser.startup.upgradeDialog.enabled=false [browser_whats_new_page.js]
--- a/toolkit/components/nimbus/ExperimentAPI.jsm +++ b/toolkit/components/nimbus/ExperimentAPI.jsm @@ -60,16 +60,20 @@ const MANIFEST = { prefsButtonIcon: { type: "string", }, }, }, "password-autocomplete": { description: "A special autocomplete UI for password fields.", }, + upgradeDialog: { + description: "The dialog shown for major upgrades", + enabledFallbackPref: "browser.startup.upgradeDialog.enabled", + }, }; function isBooleanValueDefined(value) { return typeof value === "boolean"; } const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); const { XPCOMUtils } = ChromeUtils.import(