forked from mirrors/gecko-dev
Creating non-shared scopes for frame scripts is fairly expensive. After these changes it's even more expensive. However, many frame scripts have no use for the shared scopes at all. Run-once scripts which execute in closures, for instance, make no use of them. And after bug 1472491, neither do most of our default frame scripts. MozReview-Commit-ID: 9PK7bYdQ0yh --HG-- extra : rebase_source : db2516d2f00a75e233e1957649f2b62a9299b7cd
232 lines
7 KiB
JavaScript
232 lines
7 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* 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/. */
|
|
/* globals APP_STARTUP, ADDON_INSTALL */
|
|
"use strict";
|
|
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
OnboardingTourType: "resource://onboarding/modules/OnboardingTourType.jsm",
|
|
OnboardingTelemetry: "resource://onboarding/modules/OnboardingTelemetry.jsm",
|
|
Services: "resource://gre/modules/Services.jsm",
|
|
UIState: "resource://services-sync/UIState.jsm",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
|
|
"@mozilla.org/network/protocol;1?name=resource",
|
|
"nsISubstitutingProtocolHandler");
|
|
|
|
const RESOURCE_HOST = "onboarding";
|
|
|
|
const {PREF_STRING, PREF_BOOL, PREF_INT} = Ci.nsIPrefBranch;
|
|
|
|
const BROWSER_READY_NOTIFICATION = "browser-delayed-startup-finished";
|
|
const BROWSER_SESSION_STORE_NOTIFICATION = "sessionstore-windows-restored";
|
|
const PREF_WHITELIST = [
|
|
["browser.onboarding.enabled", PREF_BOOL],
|
|
["browser.onboarding.state", PREF_STRING],
|
|
["browser.onboarding.notification.finished", PREF_BOOL],
|
|
["browser.onboarding.notification.prompt-count", PREF_INT],
|
|
["browser.onboarding.notification.last-time-of-changing-tour-sec", PREF_INT],
|
|
["browser.onboarding.notification.tour-ids-queue", PREF_STRING],
|
|
];
|
|
|
|
[
|
|
"onboarding-tour-addons",
|
|
"onboarding-tour-customize",
|
|
"onboarding-tour-default-browser",
|
|
"onboarding-tour-library",
|
|
"onboarding-tour-performance",
|
|
"onboarding-tour-private-browsing",
|
|
"onboarding-tour-screenshots",
|
|
"onboarding-tour-singlesearch",
|
|
"onboarding-tour-sync",
|
|
].forEach(tourId => PREF_WHITELIST.push([`browser.onboarding.tour.${tourId}.completed`, PREF_BOOL]));
|
|
|
|
let waitingForBrowserReady = true;
|
|
let startupData;
|
|
|
|
/**
|
|
* Set pref. Why no `getPrefs` function is due to the privilege level.
|
|
* We cannot set prefs inside a framescript but can read.
|
|
* For simplicity and efficiency, we still read prefs inside the framescript.
|
|
*
|
|
* @param {Array} prefs the array of prefs to set.
|
|
* The array element carries info to set pref, should contain
|
|
* - {String} name the pref name, such as `browser.onboarding.state`
|
|
* - {*} value the value to set
|
|
**/
|
|
function setPrefs(prefs) {
|
|
prefs.forEach(pref => {
|
|
let prefObj = PREF_WHITELIST.find(([name, ]) => name == pref.name);
|
|
if (!prefObj) {
|
|
return;
|
|
}
|
|
|
|
let [name, type] = prefObj;
|
|
|
|
switch (type) {
|
|
case PREF_BOOL:
|
|
Services.prefs.setBoolPref(name, pref.value);
|
|
break;
|
|
case PREF_INT:
|
|
Services.prefs.setIntPref(name, pref.value);
|
|
break;
|
|
case PREF_STRING:
|
|
Services.prefs.setStringPref(name, pref.value);
|
|
break;
|
|
default:
|
|
throw new TypeError(`Unexpected type (${type}) for preference ${name}.`);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* syncTourChecker listens to and maintains the login status inside, and can be
|
|
* queried at any time once initialized.
|
|
*/
|
|
let syncTourChecker = {
|
|
_registered: false,
|
|
_loggedIn: false,
|
|
|
|
isLoggedIn() {
|
|
return this._loggedIn;
|
|
},
|
|
|
|
observe(subject, topic) {
|
|
const state = UIState.get();
|
|
if (state.status == UIState.STATUS_NOT_CONFIGURED) {
|
|
this._loggedIn = false;
|
|
} else {
|
|
this.setComplete();
|
|
}
|
|
},
|
|
|
|
init() {
|
|
if (!Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
|
return;
|
|
}
|
|
// Check if we've already logged in at startup.
|
|
const state = UIState.get();
|
|
if (state.status != UIState.STATUS_NOT_CONFIGURED) {
|
|
this.setComplete();
|
|
}
|
|
this.register();
|
|
},
|
|
|
|
register() {
|
|
if (this._registered) {
|
|
return;
|
|
}
|
|
Services.obs.addObserver(this, "sync-ui-state:update");
|
|
this._registered = true;
|
|
},
|
|
|
|
setComplete() {
|
|
this._loggedIn = true;
|
|
Services.prefs.setBoolPref("browser.onboarding.tour.onboarding-tour-sync.completed", true);
|
|
},
|
|
|
|
unregister() {
|
|
if (!this._registered) {
|
|
return;
|
|
}
|
|
Services.obs.removeObserver(this, "sync-ui-state:update");
|
|
this._registered = false;
|
|
},
|
|
|
|
uninit() {
|
|
this.unregister();
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Listen and process events from content.
|
|
*/
|
|
function initContentMessageListener() {
|
|
Services.mm.addMessageListener("Onboarding:OnContentMessage", msg => {
|
|
switch (msg.data.action) {
|
|
case "set-prefs":
|
|
setPrefs(msg.data.params);
|
|
break;
|
|
case "get-login-status":
|
|
msg.target.messageManager.sendAsyncMessage("Onboarding:ResponseLoginStatus", {
|
|
isLoggedIn: syncTourChecker.isLoggedIn()
|
|
});
|
|
break;
|
|
case "ping-centre":
|
|
try {
|
|
OnboardingTelemetry.process(msg.data.params.data);
|
|
} catch (e) {
|
|
Cu.reportError(e);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* onBrowserReady - Continues startup of the add-on after browser is ready.
|
|
*/
|
|
function onBrowserReady() {
|
|
waitingForBrowserReady = false;
|
|
|
|
OnboardingTourType.check();
|
|
OnboardingTelemetry.init(startupData);
|
|
Services.mm.loadFrameScript("resource://onboarding/onboarding.js", true, true);
|
|
initContentMessageListener();
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
onBrowserReady();
|
|
break;
|
|
case BROWSER_SESSION_STORE_NOTIFICATION:
|
|
Services.obs.removeObserver(observe, BROWSER_SESSION_STORE_NOTIFICATION);
|
|
// Postpone Firefox account checking until "before handling user events"
|
|
// phase to meet performance criteria. The reason we don't postpone the
|
|
// whole onBrowserReady here is because in that way we will miss onload
|
|
// events for onboarding.js.
|
|
Services.tm.idleDispatchToMainThread(() => syncTourChecker.init());
|
|
break;
|
|
}
|
|
}
|
|
|
|
function install(aData, aReason) {}
|
|
|
|
function uninstall(aData, aReason) {}
|
|
|
|
function startup(aData, aReason) {
|
|
resProto.setSubstitutionWithFlags(RESOURCE_HOST,
|
|
Services.io.newURI("chrome/content/", null, aData.resourceURI),
|
|
resProto.ALLOW_CONTENT_ACCESS);
|
|
|
|
// Cache startup data which contains stuff like the version number, etc.
|
|
// so we can use it when we init the telemetry
|
|
startupData = aData;
|
|
// Only start Onboarding when the browser UI is ready
|
|
if (Services.startup.startingUp) {
|
|
Services.obs.addObserver(observe, BROWSER_READY_NOTIFICATION);
|
|
Services.obs.addObserver(observe, BROWSER_SESSION_STORE_NOTIFICATION);
|
|
} else {
|
|
onBrowserReady();
|
|
syncTourChecker.init();
|
|
}
|
|
}
|
|
|
|
function shutdown(aData, aReason) {
|
|
resProto.setSubstitution(RESOURCE_HOST, null);
|
|
|
|
startupData = null;
|
|
// Stop waiting for browser to be ready
|
|
if (waitingForBrowserReady) {
|
|
Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
|
|
}
|
|
syncTourChecker.uninit();
|
|
}
|