Bug 1474410 - Move ActivityStream instantiation and uninit into AboutNewTab draft
authorUrsula Sarracini <usarracini@mozilla.com>
Mon, 16 Jul 2018 11:58:35 -0400
changeset 818811 2d5c547b663c2ab28c5716b34b23dec8a1641459
parent 818682 2ed1506d1dc7db3d70a3feed95f1456bce05bbee
push id116351
push userusarracini@mozilla.com
push dateMon, 16 Jul 2018 15:58:57 +0000
bugs1474410
milestone63.0a1
Bug 1474410 - Move ActivityStream instantiation and uninit into AboutNewTab MozReview-Commit-ID: 5PupSQra62m
browser/extensions/activity-stream/bootstrap.js
browser/modules/AboutNewTab.jsm
--- a/browser/extensions/activity-stream/bootstrap.js
+++ b/browser/extensions/activity-stream/bootstrap.js
@@ -1,91 +1,24 @@
 /* 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/. */
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
 
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "resProto",
                                    "@mozilla.org/network/protocol;1?name=resource",
                                    "nsISubstitutingProtocolHandler");
 
 const RESOURCE_HOST = "activity-stream";
 
-const BROWSER_READY_NOTIFICATION = "sessionstore-windows-restored";
-const RESOURCE_BASE = "resource://activity-stream";
-
-let activityStream;
-let modulesToUnload = new Set();
-let waitingForBrowserReady = true;
-
-// Lazily load ActivityStream then find related modules to unload
-XPCOMUtils.defineLazyModuleGetter(this, "ActivityStream",
-  "resource://activity-stream/lib/ActivityStream.jsm", null, null, () => {
-    // Helper to fetch a resource directory listing and call back with each item
-    const processListing = async (uri, cb) => {
-      try {
-        (await (await fetch(uri)).text())
-          .split("\n").slice(2).forEach(line => cb(line.split(" ").slice(1)));
-      } catch (e) {
-        // Silently ignore listings that fail to load
-        // probably because the resource: has been unloaded
-      }
-    };
-
-    // Look for modules one level deeper than the top resource URI
-    processListing(RESOURCE_BASE, ([directory, , , type]) => {
-      if (type === "DIRECTORY") {
-        // Look into this directory for .jsm files
-        const subDir = `${RESOURCE_BASE}/${directory}`;
-        processListing(subDir, ([name]) => {
-          if (name && name.search(/\.jsm$/) !== -1) {
-            modulesToUnload.add(`${subDir}/${name}`);
-          }
-        });
-      }
-    });
-  });
-
-/**
- * init - Initializes an instance of ActivityStream. This could be called by
- *        the startup() function exposed by bootstrap.js.
- */
-function init() {
-  // Don't re-initialize
-  if (activityStream && activityStream.initialized) {
-    return;
-  }
-  activityStream = new ActivityStream();
-  try {
-    activityStream.init();
-  } catch (e) {
-    Cu.reportError(e);
-  }
-}
-
-/**
- * uninit - Uninitializes the activityStream instance, if it exsits.This could be
- *          called by the shutdown() function exposed by bootstrap.js.
- *
- * @param  {type} reason Reason for uninitialization. Could be uninstall, upgrade, or PREF_OFF
- */
-function uninit(reason) {
-  // Make sure to only uninit once in case both pref change and shutdown happen
-  if (activityStream) {
-    activityStream.uninit(reason);
-    activityStream = null;
-  }
-}
-
 /**
  * Check if an old pref has a custom value to migrate. Clears the pref so that
  * it's the default after migrating (to avoid future need to migrate).
  *
  * @param oldPrefName {string} Pref to check and migrate
  * @param cbIfNotDefault {function} Callback that gets the current pref value
  */
 function migratePref(oldPrefName, cbIfNotDefault) {
@@ -108,22 +41,24 @@ function migratePref(oldPrefName, cbIfNo
       break;
   }
 
   // Give the callback the current value then clear the pref
   cbIfNotDefault(Services.prefs[prefGetter](oldPrefName));
   Services.prefs.clearUserPref(oldPrefName);
 }
 
-/**
- * onBrowserReady - Continues startup of the add-on after browser is ready.
- */
-function onBrowserReady() {
-  waitingForBrowserReady = false;
-  init();
+// The functions below are required by bootstrap.js
+
+this.install = function install(data, reason) {};
+
+this.startup = function startup(data, reason) {
+  resProto.setSubstitutionWithFlags(RESOURCE_HOST,
+                                    Services.io.newURI("chrome/content/", null, data.resourceURI),
+                                    resProto.ALLOW_CONTENT_ACCESS);
 
   // Do a one time migration of Tiles about:newtab prefs that have been modified
   migratePref("browser.newtabpage.rows", rows => {
     // Just disable top sites if rows are not desired
     if (rows <= 0) {
       Services.prefs.setBoolPref("browser.newtabpage.activity-stream.feeds.topsites", false);
     } else {
       Services.prefs.setIntPref("browser.newtabpage.activity-stream.topSitesRows", rows);
@@ -135,62 +70,15 @@ function onBrowserReady() {
       Services.prefs.setBoolPref("browser.newtabpage.activity-stream.feeds.topsites", false);
     }
   });
 
   // Old activity stream topSitesCount pref showed 6 per row
   migratePref("browser.newtabpage.activity-stream.topSitesCount", count => {
     Services.prefs.setIntPref("browser.newtabpage.activity-stream.topSitesRows", Math.ceil(count / 6));
   });
-}
-
-/**
- * observe - nsIObserver callback to handle various browser notifications.
- */
-function observe(subject, topic, data) {
-  switch (topic) {
-    case BROWSER_READY_NOTIFICATION:
-      Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
-      // Avoid running synchronously during this event that's used for timing
-      Services.tm.dispatchToMainThread(() => onBrowserReady());
-      break;
-  }
-}
-
-// The functions below are required by bootstrap.js
-
-this.install = function install(data, reason) {};
-
-this.startup = function startup(data, reason) {
-  resProto.setSubstitutionWithFlags(RESOURCE_HOST,
-                                    Services.io.newURI("chrome/content/", null, data.resourceURI),
-                                    resProto.ALLOW_CONTENT_ACCESS);
-
-  // Only start Activity Stream up when the browser UI is ready
-  if (Services.startup.startingUp) {
-    Services.obs.addObserver(observe, BROWSER_READY_NOTIFICATION);
-  } else {
-    // Handle manual install or automatic install after manual uninstall
-    onBrowserReady();
-  }
 };
 
 this.shutdown = function shutdown(data, reason) {
   resProto.setSubstitution(RESOURCE_HOST, null);
-
-  // Uninitialize Activity Stream
-  uninit(reason);
-
-  // Stop waiting for browser to be ready
-  if (waitingForBrowserReady) {
-    Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
-  }
-
-  // Unload any add-on modules that might might have been imported
-  modulesToUnload.forEach(Cu.unload);
 };
 
-this.uninstall = function uninstall(data, reason) {
-  if (activityStream) {
-    activityStream.uninstall(reason);
-    activityStream = null;
-  }
-};
+this.uninstall = function uninstall(data, reason) {};
--- a/browser/modules/AboutNewTab.jsm
+++ b/browser/modules/AboutNewTab.jsm
@@ -4,72 +4,112 @@
 
 "use strict";
 
 var EXPORTED_SYMBOLS = [ "AboutNewTab" ];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-ChromeUtils.defineModuleGetter(this, "AutoMigrate",
-  "resource:///modules/AutoMigrate.jsm");
-ChromeUtils.defineModuleGetter(this, "NewTabUtils",
-  "resource://gre/modules/NewTabUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "RemotePages",
-  "resource://gre/modules/RemotePageManager.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+  ActivityStream: "resource://activity-stream/lib/ActivityStream.jsm",
+  RemotePages: "resource://gre/modules/RemotePageManager.jsm"
+});
+
+const BROWSER_READY_NOTIFICATION = "sessionstore-windows-restored";
 
 var AboutNewTab = {
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
+
+  // AboutNewTab
 
   pageListener: null,
 
   isOverridden: false,
 
+  activityStream: null,
+
+  /**
+   * init - Initializes an instance of Activity Stream if one doesn't exist already
+   *        and creates the instance of Remote Page Manager which Activity Stream
+   *        uses for message passing.
+   *
+   * @param {obj} pageListener - Optional argument. An existing instance of RemotePages
+   *                             which Activity Stream has previously made, and we
+   *                             would like to re-use.
+   */
   init(pageListener) {
     if (this.isOverridden) {
       return;
     }
+
+    // Since `init` can be called via `reset` at a later time with an existing
+    // pageListener, we want to only add the observer if we are initializing
+    // without this pageListener argument. This means it was the first call to `init`
+    if (!pageListener) {
+      Services.obs.addObserver(this, BROWSER_READY_NOTIFICATION);
+    }
+
     this.pageListener = pageListener || new RemotePages(["about:home", "about:newtab", "about:welcome"]);
-    this.pageListener.addMessageListener("NewTab:Customize", this.customize);
-    this.pageListener.addMessageListener("NewTab:MaybeShowMigrateMessage",
-      this.maybeShowMigrateMessage);
   },
 
-  maybeShowMigrateMessage({ target }) {
-    AutoMigrate.shouldShowMigratePrompt(target.browser).then((prompt) => {
-      if (prompt) {
-        AutoMigrate.showUndoNotificationBar(target.browser);
-      }
-    });
+  /**
+   * onBrowserReady - Continues the initialization of Activity Stream after browser is ready.
+   */
+  onBrowserReady() {
+    if (this.activityStream && this.activityStream.initialized) {
+       return;
+    }
+
+    this.activityStream = new ActivityStream();
+    try {
+      this.activityStream.init();
+    } catch (e) {
+      Cu.reportError(e);
+    }
   },
 
-  customize(message) {
-    NewTabUtils.allPages.enabled = message.data.enabled;
-    NewTabUtils.allPages.enhanced = message.data.enhanced;
-  },
+  /**
+   * uninit - Uninitializes Activity Stream if it exists, and destroys the pageListener
+   *        if it exists.
+   */
+  uninit() {
+    if (this.activityStream) {
+      this.activityStream.uninit();
+      this.activityStream = null;
+    }
 
-  uninit() {
     if (this.pageListener) {
       this.pageListener.destroy();
       this.pageListener = null;
     }
   },
 
   override(shouldPassPageListener) {
     this.isOverridden = true;
     const pageListener = this.pageListener;
     if (!pageListener)
       return null;
     if (shouldPassPageListener) {
       this.pageListener = null;
-      pageListener.removeMessageListener("NewTab:Customize", this.customize);
-      pageListener.removeMessageListener("NewTab:MaybeShowMigrateMessage",
-        this.maybeShowMigrateMessage);
       return pageListener;
     }
     this.uninit();
     return null;
   },
 
   reset(pageListener) {
     this.isOverridden = false;
     this.init(pageListener);
+  },
+
+  // nsIObserver implementation
+
+  observe(subject, topic, data) {
+    switch (topic) {
+      case BROWSER_READY_NOTIFICATION:
+        Services.obs.removeObserver(this, BROWSER_READY_NOTIFICATION);
+        // Avoid running synchronously during this event that's used for timing
+        Services.tm.dispatchToMainThread(() => this.onBrowserReady());
+        break;
+    }
   }
 };