mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-25 11:15:34 +00:00
Bug 1367077 - 1. Move startup utility functions into GeckoViewUtils; r=snorp
Move `addLazyGetter` and `addLazyEventListener` utility functions from GeckoViewStartup.js into GeckoViewUtils.jsm, so they can be used for both Fennec and standalone GeckoView. Also switch to "chrome-document-loaded" for loading DownloadNotifications because that's later in the startup sequence. MozReview-Commit-ID: 1caMtufkHGR
This commit is contained in:
parent
1151db8b05
commit
3dfb8bc0dc
@ -315,7 +315,7 @@ var WebrtcUI = {
|
||||
let uri = aContentWindow.document.documentURIObject;
|
||||
let host = uri.host;
|
||||
let requestor = (chromeWin.BrowserApp && chromeWin.BrowserApp.manifest) ?
|
||||
"'" + BrowserApp.manifest.name + "'" : host;
|
||||
"'" + chromeWin.BrowserApp.manifest.name + "'" : host;
|
||||
let message = Strings.browser.formatStringFromName("getUserMedia.share" + requestType + ".message", [ requestor ], 1);
|
||||
|
||||
let options = { inputs: [] };
|
||||
|
@ -2,15 +2,15 @@
|
||||
* 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/. */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AppConstants: "resource://gre/modules/AppConstants.jsm",
|
||||
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
var Strings = {};
|
||||
|
||||
@ -40,47 +40,20 @@ BrowserCLH.prototype = {
|
||||
protocolHandler.setSubstitution("android", Services.io.newURI(url));
|
||||
},
|
||||
|
||||
addObserverScripts: function(aScripts) {
|
||||
aScripts.forEach(item => {
|
||||
let {name, topics, script} = item;
|
||||
XPCOMUtils.defineLazyGetter(this, name, _ => {
|
||||
let sandbox = {};
|
||||
if (script.endsWith(".jsm")) {
|
||||
Cu.import(script, sandbox);
|
||||
} else {
|
||||
Services.scriptloader.loadSubScript(script, sandbox);
|
||||
}
|
||||
return sandbox[name];
|
||||
});
|
||||
let observer = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
if (!item.once) {
|
||||
Services.obs.addObserver(this[name], topic);
|
||||
}
|
||||
this[name].observe(subject, topic, data); // Explicitly notify new observer
|
||||
};
|
||||
topics.forEach(topic => {
|
||||
Services.obs.addObserver(observer, topic);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "app-startup":
|
||||
case "app-startup": {
|
||||
this.setResourceSubstitutions();
|
||||
|
||||
let observerScripts = [{
|
||||
name: "DownloadNotifications",
|
||||
script: "resource://gre/modules/DownloadNotifications.jsm",
|
||||
topics: ["chrome-document-interactive"],
|
||||
GeckoViewUtils.addLazyGetter(this, "DownloadNotifications", {
|
||||
module: "resource://gre/modules/DownloadNotifications.jsm",
|
||||
observers: ["chrome-document-loaded"],
|
||||
once: true,
|
||||
}];
|
||||
});
|
||||
if (AppConstants.MOZ_WEBRTC) {
|
||||
observerScripts.push({
|
||||
name: "WebrtcUI",
|
||||
GeckoViewUtils.addLazyGetter(this, "WebrtcUI", {
|
||||
script: "chrome://browser/content/WebrtcUI.js",
|
||||
topics: [
|
||||
observers: [
|
||||
"getUserMedia:ask-device-permission",
|
||||
"getUserMedia:request",
|
||||
"PeerConnection:request",
|
||||
@ -90,8 +63,8 @@ BrowserCLH.prototype = {
|
||||
],
|
||||
});
|
||||
}
|
||||
this.addObserverScripts(observerScripts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -6,8 +6,10 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
function GeckoViewStartup() {
|
||||
}
|
||||
@ -17,59 +19,6 @@ GeckoViewStartup.prototype = {
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
addLazyGetter: function({name, script, service, module,
|
||||
observers, ppmm, mm, init, once}) {
|
||||
if (script) {
|
||||
XPCOMUtils.defineLazyScriptGetter(this, name, script);
|
||||
} else if (module) {
|
||||
XPCOMUtils.defineLazyGetter(this, name, _ => {
|
||||
let sandbox = {};
|
||||
Cu.import(module, sandbox);
|
||||
if (init) {
|
||||
init.call(this, sandbox[name]);
|
||||
}
|
||||
return sandbox[name];
|
||||
});
|
||||
} else if (service) {
|
||||
XPCOMUtils.defineLazyGetter(this, name, _ =>
|
||||
Cc[service].getService(Ci.nsISupports).wrappedJSObject);
|
||||
}
|
||||
|
||||
if (observers) {
|
||||
let observer = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
if (!once) {
|
||||
Services.obs.addObserver(this[name], topic);
|
||||
}
|
||||
this[name].observe(subject, topic, data); // Explicitly notify new observer
|
||||
};
|
||||
observers.forEach(topic => Services.obs.addObserver(observer, topic));
|
||||
}
|
||||
|
||||
if (ppmm || mm) {
|
||||
let target = ppmm ? Services.ppmm : Services.mm;
|
||||
let listener = msg => {
|
||||
target.removeMessageListener(msg.name, listener);
|
||||
if (!once) {
|
||||
target.addMessageListener(msg.name, this[name]);
|
||||
}
|
||||
this[name].receiveMessage(msg);
|
||||
};
|
||||
(ppmm || mm).forEach(msg => target.addMessageListener(msg, listener));
|
||||
}
|
||||
},
|
||||
|
||||
addLazyEventListener: function({name, target, events, options}) {
|
||||
let listener = event => {
|
||||
if (!options || !options.once) {
|
||||
target.removeEventListener(event.type, listener, options);
|
||||
target.addEventListener(event.type, this[name], options);
|
||||
}
|
||||
this[name].handleEvent(event);
|
||||
};
|
||||
events.forEach(event => target.addEventListener(event, listener, options));
|
||||
},
|
||||
|
||||
/* ---------- nsIObserver ---------- */
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
@ -78,8 +27,7 @@ GeckoViewStartup.prototype = {
|
||||
Services.obs.addObserver(this, "chrome-document-global-created");
|
||||
Services.obs.addObserver(this, "content-document-global-created");
|
||||
|
||||
this.addLazyGetter({
|
||||
name: "GeckoViewPermission",
|
||||
GeckoViewUtils.addLazyGetter(this, "GeckoViewPermission", {
|
||||
service: "@mozilla.org/content-permission/prompt;1",
|
||||
observers: [
|
||||
"getUserMedia:ask-device-permission",
|
||||
@ -90,8 +38,7 @@ GeckoViewStartup.prototype = {
|
||||
|
||||
if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
// Content process only.
|
||||
this.addLazyGetter({
|
||||
name: "GeckoViewPrompt",
|
||||
GeckoViewUtils.addLazyGetter(this, "GeckoViewPrompt", {
|
||||
service: "@mozilla.org/prompter;1",
|
||||
});
|
||||
}
|
||||
@ -101,8 +48,7 @@ GeckoViewStartup.prototype = {
|
||||
case "profile-after-change": {
|
||||
// Parent process only.
|
||||
// ContentPrefServiceParent is needed for e10s file picker.
|
||||
this.addLazyGetter({
|
||||
name: "ContentPrefServiceParent",
|
||||
GeckoViewUtils.addLazyGetter(this, "ContentPrefServiceParent", {
|
||||
module: "resource://gre/modules/ContentPrefServiceParent.jsm",
|
||||
init: cpsp => cpsp.alwaysInit(),
|
||||
ppmm: [
|
||||
@ -112,8 +58,7 @@ GeckoViewStartup.prototype = {
|
||||
],
|
||||
});
|
||||
|
||||
this.addLazyGetter({
|
||||
name: "GeckoViewPrompt",
|
||||
GeckoViewUtils.addLazyGetter(this, "GeckoViewPrompt", {
|
||||
service: "@mozilla.org/prompter;1",
|
||||
mm: [
|
||||
"GeckoView:Prompt",
|
||||
@ -124,22 +69,14 @@ GeckoViewStartup.prototype = {
|
||||
|
||||
case "chrome-document-global-created":
|
||||
case "content-document-global-created": {
|
||||
let win = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell).QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
let win = GeckoViewUtils.getChromeWindow(aSubject);
|
||||
if (win !== aSubject) {
|
||||
// Only attach to top-level windows.
|
||||
return;
|
||||
}
|
||||
|
||||
this.addLazyEventListener({
|
||||
name: "GeckoViewPrompt",
|
||||
target: win,
|
||||
events: [
|
||||
"click",
|
||||
"contextmenu",
|
||||
],
|
||||
GeckoViewUtils.addLazyEventListener(win, ["click", "contextmenu"], {
|
||||
handler: _ => this.GeckoViewPrompt,
|
||||
options: {
|
||||
capture: false,
|
||||
mozSystemGroup: true,
|
||||
|
@ -47,7 +47,7 @@ var DownloadNotifications = {
|
||||
_notificationKey: "downloads",
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic === "chrome-document-interactive") {
|
||||
if (topic === "chrome-document-loaded") {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
|
167
mobile/android/modules/geckoview/GeckoViewUtils.jsm
Normal file
167
mobile/android/modules/geckoview/GeckoViewUtils.jsm
Normal file
@ -0,0 +1,167 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
EventDispatcher: "resource://gre/modules/Messaging.jsm",
|
||||
});
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["GeckoViewUtils"];
|
||||
|
||||
var GeckoViewUtils = {
|
||||
/**
|
||||
* Define a lazy getter that loads an object from external code, and
|
||||
* optionally handles observer and/or message manager notifications for the
|
||||
* object, so the object only loads when a notification is received.
|
||||
*
|
||||
* @param scope Scope for holding the loaded object.
|
||||
* @param name Name of the object to load.
|
||||
* @param script If specified, load the object from a JS subscript.
|
||||
* @param service If specified, load the object from a JS component; the
|
||||
* component must include the line
|
||||
* "this.wrappedJSObject = this;" in its constructor.
|
||||
* @param module If specified, load the object from a JS module.
|
||||
* @param init For non-scripts, optional post-load initialization function.
|
||||
* @param observers If specified, listen to specified observer notifications.
|
||||
* @param ppmm If specified, listen to specified process messages.
|
||||
* @param mm If specified, listen to specified frame messages.
|
||||
* @param ged If specified, listen to specified global EventDispatcher events.
|
||||
* @param once If specified, only listen to the specified
|
||||
* notifications/messages once.
|
||||
*/
|
||||
addLazyGetter: function(scope, name, {script, service, module, handler,
|
||||
observers, ppmm, mm, ged, init, once}) {
|
||||
if (script) {
|
||||
XPCOMUtils.defineLazyScriptGetter(scope, name, script);
|
||||
} else {
|
||||
XPCOMUtils.defineLazyGetter(scope, name, _ => {
|
||||
let ret = undefined;
|
||||
if (module) {
|
||||
ret = Cu.import(module, {})[name];
|
||||
} else if (service) {
|
||||
ret = Cc[service].getService(Ci.nsISupports).wrappedJSObject;
|
||||
} else if (typeof handler === "function") {
|
||||
ret = {
|
||||
handleEvent: handler,
|
||||
observe: handler,
|
||||
onEvent: handler,
|
||||
receiveMessage: handler,
|
||||
};
|
||||
} else if (handler) {
|
||||
ret = handler;
|
||||
}
|
||||
if (ret && init) {
|
||||
init.call(scope, ret);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
|
||||
if (observers) {
|
||||
let observer = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
if (!once) {
|
||||
Services.obs.addObserver(scope[name], topic);
|
||||
}
|
||||
scope[name].observe(subject, topic, data); // Explicitly notify new observer
|
||||
};
|
||||
observers.forEach(topic => Services.obs.addObserver(observer, topic));
|
||||
}
|
||||
|
||||
let addMMListener = (target, names) => {
|
||||
let listener = msg => {
|
||||
target.removeMessageListener(msg.name, listener);
|
||||
if (!once) {
|
||||
target.addMessageListener(msg.name, scope[name]);
|
||||
}
|
||||
scope[name].receiveMessage(msg);
|
||||
};
|
||||
names.forEach(msg => target.addMessageListener(msg, listener));
|
||||
};
|
||||
if (ppmm) {
|
||||
addMMListener(Services.ppmm, ppmm);
|
||||
}
|
||||
if (mm) {
|
||||
addMMListener(Services.mm, mm);
|
||||
}
|
||||
|
||||
if (ged) {
|
||||
let listener = (event, data, callback) => {
|
||||
EventDispatcher.instance.unregisterListener(listener, event);
|
||||
if (!once) {
|
||||
EventDispatcher.instance.registerListener(scope[name], event);
|
||||
}
|
||||
scope[name].onEvent(event, data, callback);
|
||||
};
|
||||
EventDispatcher.instance.registerListener(listener, ged);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add lazy event listeners that only load the actual handler when an event
|
||||
* is being handled.
|
||||
*
|
||||
* @param target Event target for the event listeners.
|
||||
* @param events Event name as a string or array.
|
||||
* @param handler If specified, function that, for a given event, returns the
|
||||
* actual event handler as an object or an array of objects.
|
||||
* If handler is not specified, the actual event handler is
|
||||
* specified using the scope and name pair.
|
||||
* @param scope See handler.
|
||||
* @param name See handler.
|
||||
* @param options Options for addEventListener.
|
||||
*/
|
||||
addLazyEventListener: function(target, events, {handler, scope, name, options}) {
|
||||
if (!handler) {
|
||||
handler = (_ => Array.isArray(name) ? name.map(n => scope[n]) : scope[name]);
|
||||
}
|
||||
let listener = event => {
|
||||
let handlers = handler(event);
|
||||
if (!handlers) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(handlers)) {
|
||||
handlers = [handlers];
|
||||
}
|
||||
if (!options || !options.once) {
|
||||
target.removeEventListener(event.type, listener, options);
|
||||
handlers.forEach(handler => target.addEventListener(event.type, handler, options));
|
||||
}
|
||||
handlers.forEach(handler => handler.handleEvent(event));
|
||||
};
|
||||
if (Array.isArray(events)) {
|
||||
events.forEach(event => target.addEventListener(event, listener, options));
|
||||
} else {
|
||||
target.addEventListener(events, listener, options);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the outermost chrome DOM window (the XUL window) for a given DOM
|
||||
* window.
|
||||
*
|
||||
* @param aWin a DOM window.
|
||||
*/
|
||||
getChromeWindow: function(aWin) {
|
||||
return aWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell).QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the per-nsWindow EventDispatcher for a given DOM window.
|
||||
*
|
||||
* @param aWin a DOM window.
|
||||
*/
|
||||
getDispatcherForWindow: function(aWin) {
|
||||
let win = this.getChromeWindow(aWin.top);
|
||||
return win.WindowEventDispatcher || EventDispatcher.for(win);
|
||||
},
|
||||
};
|
@ -13,6 +13,7 @@ EXTRA_JS_MODULES += [
|
||||
'GeckoViewProgress.jsm',
|
||||
'GeckoViewScroll.jsm',
|
||||
'GeckoViewSettings.jsm',
|
||||
'GeckoViewUtils.jsm',
|
||||
'GeckoViewTab.jsm',
|
||||
'Messaging.jsm',
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user