forked from mirrors/gecko-dev
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
266 lines
7 KiB
JavaScript
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"];
|