fune/browser/modules/AboutNewTab.jsm
Mike Conley 8ba260392e Bug 1619992 - Split AboutNewTabService into AboutNewTabParentService and AboutNewTabChildService. r=perftest-reviewers,Mardak,sparky
This patch does the following:
* Moves most logic for initiating about:home / about:newtab into AboutNewTab.jsm
* Makes AboutNewTab the API surface for overriding the default about:newtab URLs.
* Reduces the surface of nsIAboutNewTabService, and makes the properties read-only
* Splits the remaining code in the nsIAboutNewTabService into an implementation for
  the parent process, and one for content processes.

This split will hopefully help reduce confusion about which code in
AboutNewTabService is running in which process.

Differential Revision: https://phabricator.services.mozilla.com/D65569

--HG--
rename : browser/components/newtab/test/xpcshell/test_AboutNewTabService.js => browser/components/newtab/test/xpcshell/test_AboutNewTab.js
extra : moz-landing-system : lando
2020-03-11 03:10:29 +00:00

266 lines
7 KiB
JavaScript

/* 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";
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ActivityStream: "resource://activity-stream/lib/ActivityStream.jsm",
RemotePages:
"resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm",
});
const ABOUT_URL = "about:newtab";
const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
const TOPIC_APP_QUIT = "quit-application-granted";
const BROWSER_READY_NOTIFICATION = "sessionstore-windows-restored";
const AboutNewTab = {
QueryInterface: ChromeUtils.generateQI([
Ci.nsIObserver,
Ci.nsISupportsWeakReference,
]),
// AboutNewTab
initialized: false,
pageListener: null,
isPageListenerOverridden: false,
willNotifyUser: false,
_activityStreamEnabled: false,
activityStream: null,
activityStreamDebug: false,
_newTabURL: ABOUT_URL,
_newTabURLOverridden: false,
/**
* 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) {
Services.obs.addObserver(this, TOPIC_APP_QUIT);
if (!AppConstants.RELEASE_OR_BETA) {
XPCOMUtils.defineLazyPreferenceGetter(
this,
"activityStreamDebug",
PREF_ACTIVITY_STREAM_DEBUG,
false,
() => {
this.notifyChange();
}
);
}
XPCOMUtils.defineLazyPreferenceGetter(
this,
"privilegedAboutProcessEnabled",
"browser.tabs.remote.separatePrivilegedContentProcess",
false,
() => {
this.notifyChange();
}
);
// More initialization happens here
this.toggleActivityStream(true);
this.initialized = true;
if (this.isPageListenerOverridden) {
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"]);
},
/**
* React to changes to the activity stream being enabled or not.
*
* This will only act if there is a change of state and if not overridden.
*
* @returns {Boolean} Returns if there has been a state change
*
* @param {Boolean} stateEnabled activity stream enabled state to set to
* @param {Boolean} forceState force state change
*/
toggleActivityStream(stateEnabled, forceState = false) {
if (
!forceState &&
(this._newTabURLOverridden ||
stateEnabled === this._activityStreamEnabled)
) {
// exit there is no change of state
return false;
}
if (stateEnabled) {
this._activityStreamEnabled = true;
} else {
this._activityStreamEnabled = false;
}
this._newTabURL = ABOUT_URL;
return true;
},
get newTabURL() {
return this._newTabURL;
},
set newTabURL(aNewTabURL) {
let newTabURL = aNewTabURL.trim();
if (newTabURL === ABOUT_URL) {
// avoid infinite redirects in case one sets the URL to about:newtab
this.resetNewTabURL();
return;
} else if (newTabURL === "") {
newTabURL = "about:blank";
}
this.toggleActivityStream(false);
this._newTabURL = newTabURL;
this._newTabURLOverridden = true;
this.notifyChange();
},
get newTabURLOverridden() {
return this._newTabURLOverridden;
},
get activityStreamEnabled() {
return this._activityStreamEnabled;
},
resetNewTabURL() {
this._newTabURLOverridden = false;
this._newTabURL = ABOUT_URL;
this.toggleActivityStream(true, true);
this.notifyChange();
},
notifyChange() {
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
},
/**
* 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);
}
},
/**
* uninit - Uninitializes Activity Stream if it exists, and destroys the pageListener
* if it exists.
*/
uninit() {
if (this.activityStream) {
this.activityStream.uninit();
this.activityStream = null;
}
if (this.pageListener) {
this.pageListener.destroy();
this.pageListener = null;
}
this.initialized = false;
},
overridePageListener(shouldPassPageListener) {
this.isPageListenerOverridden = true;
const pageListener = this.pageListener;
if (!pageListener) {
return null;
}
if (shouldPassPageListener) {
this.pageListener = null;
return pageListener;
}
this.uninit();
return null;
},
reset(pageListener) {
this.isPageListenerOverridden = false;
this.init(pageListener);
},
getTopSites() {
return this.activityStream
? this.activityStream.store.getState().TopSites.rows
: [];
},
_alreadyRecordedTopsitesPainted: false,
_nonDefaultStartup: false,
noteNonDefaultStartup() {
this._nonDefaultStartup = true;
},
maybeRecordTopsitesPainted(timestamp) {
if (this._alreadyRecordedTopsitesPainted || this._nonDefaultStartup) {
return;
}
const SCALAR_KEY = "timestamps.about_home_topsites_first_paint";
let startupInfo = Services.startup.getStartupInfo();
let processStartTs = startupInfo.process.getTime();
let delta = Math.round(timestamp - processStartTs);
Services.telemetry.scalarSet(SCALAR_KEY, delta);
this._alreadyRecordedTopsitesPainted = true;
},
// nsIObserver implementation
observe(subject, topic, data) {
switch (topic) {
case TOPIC_APP_QUIT: {
this.uninit();
break;
}
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;
}
}
},
};
var EXPORTED_SYMBOLS = ["AboutNewTab"];