Bug 1568692 - Show a page like what's new on startup once but not dependent on major version bump. r=k88hudson, a=RyanVM
authorEd Lee <edilee@mozilla.com>
Tue, 30 Jul 2019 17:39:34 +0000
changeset 541945 3a71ae2fd8258a8323a9ced755e4536a79ef44a6
parent 541944 6cecf42542f3bee7c0220dcc76b05056e3c15c32
child 541946 8107e7f68e126fb10e697ee135c4589a8b72dd73
push id11788
push userryanvm@gmail.com
push dateThu, 15 Aug 2019 13:21:51 +0000
treeherdermozilla-beta@8107e7f68e12 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersk88hudson, RyanVM
bugs1568692
milestone69.0
Bug 1568692 - Show a page like what's new on startup once but not dependent on major version bump. r=k88hudson, a=RyanVM Differential Revision: https://phabricator.services.mozilla.com/D41837
browser/components/BrowserContentHandler.jsm
browser/components/tests/browser/browser.ini
browser/components/tests/browser/browser_bug538331.js
browser/components/tests/browser/browser_startup_homepage.js
--- a/browser/components/BrowserContentHandler.jsm
+++ b/browser/components/BrowserContentHandler.jsm
@@ -235,30 +235,28 @@ function getPostUpdateOverridePage(defau
 function openBrowserWindow(
   cmdLine,
   triggeringPrincipal,
   urlOrUrlList,
   postData = null,
   forcePrivate = false
 ) {
   let chromeURL = AppConstants.BROWSER_CHROME_URL;
+  const isStartup =
+    cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH;
 
   let args;
   if (!urlOrUrlList) {
     // Just pass in the defaultArgs directly. We'll use system principal on the other end.
-    args = [gBrowserContentHandler.defaultArgs];
+    args = [gBrowserContentHandler.getArgs(isStartup)];
   } else {
     let pService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
       Ci.nsIToolkitProfileService
     );
-    if (
-      cmdLine &&
-      cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
-      pService.createdAlternateProfile
-    ) {
+    if (isStartup && pService.createdAlternateProfile) {
       let url = getNewInstallPage();
       if (Array.isArray(urlOrUrlList)) {
         urlOrUrlList.unshift(url);
       } else {
         urlOrUrlList = [url, urlOrUrlList];
       }
     }
 
@@ -299,17 +297,17 @@ function openBrowserWindow(
         undefined, // user context id
         null, // origin principal
         null, // origin storage principal
         triggeringPrincipal,
       ];
     }
   }
 
-  if (cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
+  if (isStartup) {
     let win = Services.wm.getMostRecentWindow("navigator:blank");
     if (win) {
       // Remove the windowtype of our blank window so that we don't close it
       // later on when seeing cmdLine.preventDefault is true.
       win.document.documentElement.removeAttribute("windowtype");
 
       if (forcePrivate) {
         win.docShell.QueryInterface(
@@ -607,16 +605,20 @@ nsBrowserContentHandler.prototype = {
       "  --search <term>    Search <term> with your default search engine.\n";
     info += "  --setDefaultBrowser Set this app as the default browser.\n";
     return info;
   },
 
   /* nsIBrowserHandler */
 
   get defaultArgs() {
+    return this.getArgs();
+  },
+
+  getArgs(isStartup = false) {
     var prefb = Services.prefs;
 
     if (!gFirstWindow) {
       gFirstWindow = true;
       if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) {
         return "about:privatebrowsing";
       }
     }
@@ -690,16 +692,34 @@ nsBrowserContentHandler.prototype = {
       }
     } catch (ex) {}
 
     // formatURLPref might return "about:blank" if getting the pref fails
     if (overridePage == "about:blank") {
       overridePage = "";
     }
 
+    // Allow showing a one-time startup override if we're not showing one
+    const ONCE_PREF = "browser.startup.homepage_override.once";
+    if (isStartup && overridePage == "" && prefb.prefHasUserValue(ONCE_PREF)) {
+      try {
+        // Show if we haven't passed the expiration or there's no expiration
+        const { expire, url } = JSON.parse(
+          Services.urlFormatter.formatURLPref(ONCE_PREF)
+        );
+        if (!(Date.now() > expire) && typeof url == "string") {
+          overridePage = url;
+        }
+      } catch (ex) {
+        // Invalid json pref, so ignore (and clear below)
+      } finally {
+        prefb.clearUserPref(ONCE_PREF);
+      }
+    }
+
     if (!additionalPage) {
       additionalPage = LaterRun.getURL() || "";
     }
 
     if (additionalPage && additionalPage != "about:blank") {
       if (overridePage) {
         overridePage += "|" + additionalPage;
       } else {
--- a/browser/components/tests/browser/browser.ini
+++ b/browser/components/tests/browser/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
 
 [browser_bug538331.js]
 skip-if = !updater
 reason = test depends on update channel
 [browser_contentpermissionprompt.js]
 [browser_default_bookmark_toolbar_visibility.js]
 [browser_initial_tab_remoteType.js]
+[browser_startup_homepage.js]
 [browser_urlbar_matchBuckets_migration60.js]
--- a/browser/components/tests/browser/browser_bug538331.js
+++ b/browser/components/tests/browser/browser_bug538331.js
@@ -1,15 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const PREF_POSTUPDATE = "app.update.postupdate";
+const PREF_PAGE = "browser.startup.page";
 const PREF_MSTONE = "browser.startup.homepage_override.mstone";
 const PREF_OVERRIDE_URL = "startup.homepage_override_url";
 
 const DEFAULT_PREF_URL = "http://pref.example.com/";
 const DEFAULT_UPDATE_URL = "http://example.com/";
 
 const XML_EMPTY =
   '<?xml version="1.0"?><updates xmlns=' +
@@ -77,38 +78,42 @@ const BCH_TESTS = [
     actions: "silent",
   },
   {
     description: "update with 'silent showURL extra' for actions and openURL",
     actions: "silent showURL extra",
   },
 ];
 
+var gOriginalPage;
 var gOriginalMStone;
 var gOriginalOverrideURL;
 
 function test() {
   waitForExplicitFinish();
 
   // Reset the startup page pref since it may have been set by other tests
-  // and we will assume it is default.
-  Services.prefs.clearUserPref("browser.startup.page");
+  // and we will assume it is (non-test) default.
+  gOriginalPage = Services.prefs.getIntPref(PREF_PAGE);
+  Services.prefs.clearUserPref(PREF_PAGE);
 
   if (Services.prefs.prefHasUserValue(PREF_MSTONE)) {
     gOriginalMStone = Services.prefs.getCharPref(PREF_MSTONE);
   }
 
   if (Services.prefs.prefHasUserValue(PREF_OVERRIDE_URL)) {
     gOriginalOverrideURL = Services.prefs.getCharPref(PREF_OVERRIDE_URL);
   }
 
   testDefaultArgs();
 }
 
 function finish_test() {
+  Services.prefs.setIntPref(PREF_PAGE, gOriginalPage);
+
   // Reset browser.startup.homepage_override.mstone to the original value or
   // clear it if it didn't exist.
   if (gOriginalMStone) {
     Services.prefs.setCharPref(PREF_MSTONE, gOriginalMStone);
   } else if (Services.prefs.prefHasUserValue(PREF_MSTONE)) {
     Services.prefs.clearUserPref(PREF_MSTONE);
   }
 
new file mode 100644
--- /dev/null
+++ b/browser/components/tests/browser/browser_startup_homepage.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+async function checkArgs(message, expect, prefs = {}) {
+  info(`Setting prefs: ${JSON.stringify(prefs)}`);
+  await SpecialPowers.pushPrefEnv({
+    set: Object.entries(prefs).map(keyVal => {
+      if (typeof keyVal[1] == "object") {
+        keyVal[1] = JSON.stringify(keyVal[1]);
+      }
+      return keyVal;
+    }),
+  });
+
+  // Check the defaultArgs for startup behavior
+  Assert.equal(
+    Cc["@mozilla.org/browser/clh;1"]
+      .getService(Ci.nsIBrowserHandler)
+      .wrappedJSObject.getArgs(true),
+    expect,
+    message
+  );
+}
+
+add_task(async function test_once_expire() {
+  const url = "https://www.mozilla.org/";
+  await checkArgs("no expiration", url, {
+    "browser.startup.homepage_override.once": { url },
+  });
+
+  await checkArgs("expired", "about:blank", {
+    "browser.startup.homepage_override.once": { expire: 0, url },
+  });
+
+  await checkArgs("not expired", url, {
+    "browser.startup.homepage_override.once": { expire: Date.now() * 2, url },
+  });
+});
+
+add_task(async function test_once_invalid() {
+  await checkArgs("not json", "about:blank", {
+    "browser.startup.homepage_override.once": "https://not.json",
+  });
+
+  await checkArgs("not string", "about:blank", {
+    "browser.startup.homepage_override.once": { url: 5 },
+  });
+});
+
+add_task(async function test_once() {
+  await checkArgs("initial test prefs (no homepage)", "about:blank");
+
+  const url = "https://www.mozilla.org/";
+  await checkArgs("override once", url, {
+    "browser.startup.homepage_override.once": { url },
+  });
+
+  await checkArgs("once cleared", "about:blank");
+
+  await checkArgs("formatted", "https://www.mozilla.org/en-US", {
+    "browser.startup.homepage_override.once": {
+      url: "https://www.mozilla.org/%LOCALE%",
+    },
+  });
+
+  await checkArgs("use homepage", "about:home", {
+    "browser.startup.page": 1,
+  });
+
+  await checkArgs("once with homepage", `${url}|about:home`, {
+    "browser.startup.homepage_override.once": { url },
+  });
+
+  await checkArgs("once cleared again", "about:home");
+
+  await checkArgs("prefer major version override", `about:welcome|about:home`, {
+    "browser.startup.homepage_override.mstone": "1.0",
+    "browser.startup.homepage_override.once": { url },
+    "startup.homepage_override_url": "about:welcome",
+  });
+
+  await checkArgs("once after major", `${url}|about:home`);
+
+  await checkArgs("once cleared yet again", "about:home");
+});