зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1160923 - [B2G] Waiting for explicit mozContentEvent before sending out mozChromeEvents, r=vingtetun, f=ochaumeau
This commit is contained in:
Родитель
2c103b0ace
Коммит
c251097169
|
@ -190,7 +190,7 @@ var developerHUD = {
|
|||
* metrics, and how to notify the front-end when metrics have changed.
|
||||
*/
|
||||
function Target(frame, actor) {
|
||||
this._frame = frame;
|
||||
this.frame = frame;
|
||||
this.actor = actor;
|
||||
this.metrics = new Map();
|
||||
this._appName = null;
|
||||
|
@ -198,15 +198,8 @@ function Target(frame, actor) {
|
|||
|
||||
Target.prototype = {
|
||||
|
||||
get frame() {
|
||||
let frame = this._frame;
|
||||
let systemapp = document.querySelector('#systemapp');
|
||||
|
||||
return (frame === systemapp ? getContentWindow() : frame);
|
||||
},
|
||||
|
||||
get manifest() {
|
||||
return this._frame.appManifestURL;
|
||||
return this.frame.appManifestURL;
|
||||
},
|
||||
|
||||
get appName() {
|
||||
|
|
|
@ -82,10 +82,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "SafeMode",
|
|||
|
||||
window.performance.measure('gecko-shell-jsm-loaded', 'gecko-shell-loadstart');
|
||||
|
||||
function getContentWindow() {
|
||||
return shell.contentBrowser.contentWindow;
|
||||
}
|
||||
|
||||
function debug(str) {
|
||||
dump(' -*- Shell.js: ' + str + '\n');
|
||||
}
|
||||
|
@ -388,7 +384,7 @@ var shell = {
|
|||
CaptivePortalLoginHelper.init();
|
||||
|
||||
this.contentBrowser.src = homeURL;
|
||||
this.isHomeLoaded = false;
|
||||
this._isEventListenerReady = false;
|
||||
|
||||
window.performance.mark('gecko-shell-system-frame-set');
|
||||
|
||||
|
@ -480,6 +476,13 @@ var shell = {
|
|||
this.contentBrowser.setVisible(true);
|
||||
}
|
||||
break;
|
||||
case 'load':
|
||||
if (content.document.location == 'about:blank') {
|
||||
return;
|
||||
}
|
||||
content.removeEventListener('load', this, true);
|
||||
this.notifyContentWindowLoaded();
|
||||
break;
|
||||
case 'mozbrowserloadstart':
|
||||
if (content.document.location == 'about:blank') {
|
||||
this.contentBrowser.addEventListener('mozbrowserlocationchange', this, true);
|
||||
|
@ -586,9 +589,12 @@ var shell = {
|
|||
break;
|
||||
case 'MozAfterPaint':
|
||||
window.removeEventListener('MozAfterPaint', this);
|
||||
this.sendChromeEvent({
|
||||
// This event should be sent before System app returns with
|
||||
// system-message-listener-ready mozContentEvent, because it's on
|
||||
// the critical launch path of the app.
|
||||
SystemAppProxy._sendCustomEvent('mozChromeEvent', {
|
||||
type: 'system-first-paint'
|
||||
});
|
||||
}, /* noPending */ true);
|
||||
break;
|
||||
case 'unload':
|
||||
this.stop();
|
||||
|
@ -610,6 +616,14 @@ var shell = {
|
|||
|
||||
// Send an event to a specific window, document or element.
|
||||
sendEvent: function shell_sendEvent(target, type, details) {
|
||||
if (target === this.contentBrowser) {
|
||||
// We must ask SystemAppProxy to send the event in this case so
|
||||
// that event would be dispatched from frame.contentWindow instead of
|
||||
// on the System app frame.
|
||||
SystemAppProxy._sendCustomEvent(type, details);
|
||||
return;
|
||||
}
|
||||
|
||||
let doc = target.document || target.ownerDocument || target;
|
||||
let event = doc.createEvent('CustomEvent');
|
||||
event.initCustomEvent(type, true, true, details ? details : {});
|
||||
|
@ -617,21 +631,10 @@ var shell = {
|
|||
},
|
||||
|
||||
sendCustomEvent: function shell_sendCustomEvent(type, details) {
|
||||
let target = getContentWindow();
|
||||
let payload = details ? Cu.cloneInto(details, target) : {};
|
||||
this.sendEvent(target, type, payload);
|
||||
SystemAppProxy._sendCustomEvent(type, details);
|
||||
},
|
||||
|
||||
sendChromeEvent: function shell_sendChromeEvent(details) {
|
||||
if (!this.isHomeLoaded) {
|
||||
if (!('pendingChromeEvents' in this)) {
|
||||
this.pendingChromeEvents = [];
|
||||
}
|
||||
|
||||
this.pendingChromeEvents.push(details);
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendCustomEvent("mozChromeEvent", details);
|
||||
},
|
||||
|
||||
|
@ -672,6 +675,7 @@ var shell = {
|
|||
this.contentBrowser.removeEventListener('mozbrowserlocationchange', this, true);
|
||||
|
||||
let content = this.contentBrowser.contentWindow;
|
||||
content.addEventListener('load', this, true);
|
||||
|
||||
this.reportCrash(true);
|
||||
|
||||
|
@ -685,28 +689,7 @@ var shell = {
|
|||
Cu.import('resource://gre/modules/OperatorApps.jsm');
|
||||
#endif
|
||||
|
||||
content.addEventListener('load', function shell_homeLoaded() {
|
||||
content.removeEventListener('load', shell_homeLoaded);
|
||||
shell.isHomeLoaded = true;
|
||||
|
||||
if (Services.prefs.getBoolPref('b2g.orientation.animate')) {
|
||||
Cu.import('resource://gre/modules/OrientationChangeHandler.jsm');
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
libcutils.property_set('sys.boot_completed', '1');
|
||||
#endif
|
||||
|
||||
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
|
||||
|
||||
SystemAppProxy.setIsReady();
|
||||
if ('pendingChromeEvents' in shell) {
|
||||
shell.pendingChromeEvents.forEach((shell.sendChromeEvent).bind(shell));
|
||||
}
|
||||
delete shell.pendingChromeEvents;
|
||||
});
|
||||
|
||||
shell.handleCmdLine();
|
||||
this.handleCmdLine();
|
||||
},
|
||||
|
||||
handleCmdLine: function shell_handleCmdLine() {
|
||||
|
@ -727,6 +710,38 @@ var shell = {
|
|||
}
|
||||
#endif
|
||||
},
|
||||
|
||||
// This gets called when window.onload fires on the System app content window,
|
||||
// which means things in <html> are parsed and statically referenced <script>s
|
||||
// and <script defer>s are loaded and run.
|
||||
notifyContentWindowLoaded: function shell_notifyContentWindowLoaded() {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
libcutils.property_set('sys.boot_completed', '1');
|
||||
#endif
|
||||
|
||||
// This will cause Gonk Widget to remove boot animation from the screen
|
||||
// and reveals the page.
|
||||
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
|
||||
|
||||
SystemAppProxy.setIsLoaded();
|
||||
},
|
||||
|
||||
// This gets called when the content sends us system-message-listener-ready
|
||||
// mozContentEvent, OR when an observer message tell us we should consider
|
||||
// the content as ready.
|
||||
notifyEventListenerReady: function shell_notifyEventListenerReady() {
|
||||
if (this._isEventListenerReady) {
|
||||
Cu.reportError('shell.js: SystemApp has already been declared as being ready.');
|
||||
return;
|
||||
}
|
||||
this._isEventListenerReady = true;
|
||||
|
||||
if (Services.prefs.getBoolPref('b2g.orientation.animate')) {
|
||||
Cu.import('resource://gre/modules/OrientationChangeHandler.jsm');
|
||||
}
|
||||
|
||||
SystemAppProxy.setIsReady();
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(function onFullscreenOriginChange(subject, topic, data) {
|
||||
|
@ -734,11 +749,13 @@ Services.obs.addObserver(function onFullscreenOriginChange(subject, topic, data)
|
|||
fullscreenorigin: data });
|
||||
}, "fullscreen-origin-change", false);
|
||||
|
||||
DOMApplicationRegistry.registryStarted.then(function () {
|
||||
shell.sendChromeEvent({ type: 'webapps-registry-start' });
|
||||
});
|
||||
DOMApplicationRegistry.registryReady.then(function () {
|
||||
shell.sendChromeEvent({ type: 'webapps-registry-ready' });
|
||||
// This event should be sent before System app returns with
|
||||
// system-message-listener-ready mozContentEvent, because it's on
|
||||
// the critical launch path of the app.
|
||||
SystemAppProxy._sendCustomEvent('mozChromeEvent', {
|
||||
type: 'webapps-registry-ready'
|
||||
}, /* noPending */ true);
|
||||
});
|
||||
|
||||
Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
|
||||
|
@ -752,6 +769,10 @@ Services.obs.addObserver(function(subject, topic, data) {
|
|||
shell.sendCustomEvent('mozmemorypressure');
|
||||
}, 'memory-pressure', false);
|
||||
|
||||
Services.obs.addObserver(function(subject, topic, data) {
|
||||
shell.notifyEventListenerReady();
|
||||
}, 'system-message-listener-ready', false);
|
||||
|
||||
var permissionMap = new Map([
|
||||
['unknown', Services.perms.UNKNOWN_ACTION],
|
||||
['allow', Services.perms.ALLOW_ACTION],
|
||||
|
|
|
@ -13,8 +13,10 @@ this.EXPORTED_SYMBOLS = ['SystemAppProxy'];
|
|||
|
||||
var SystemAppProxy = {
|
||||
_frame: null,
|
||||
_isLoaded: false,
|
||||
_isReady: false,
|
||||
_pendingEvents: [],
|
||||
_pendingLoadedEvents: [],
|
||||
_pendingReadyEvents: [],
|
||||
_pendingListeners: [],
|
||||
|
||||
// To call when a new system app iframe is created
|
||||
|
@ -34,18 +36,38 @@ var SystemAppProxy = {
|
|||
return this._frame;
|
||||
},
|
||||
|
||||
// To call when the load event of the System app document is triggered.
|
||||
// i.e. everything that is not lazily loaded are run and done.
|
||||
setIsLoaded: function () {
|
||||
if (this._isLoaded) {
|
||||
Cu.reportError('SystemApp has already been declared as being loaded.');
|
||||
}
|
||||
this._isLoaded = true;
|
||||
|
||||
// Dispatch all events being queued while the system app was still loading
|
||||
this._pendingLoadedEvents
|
||||
.forEach(([type, details]) =>
|
||||
this._sendCustomEvent(type, details, true));
|
||||
this._pendingLoadedEvents = [];
|
||||
},
|
||||
|
||||
// To call when it is ready to receive events
|
||||
// i.e. when system-message-listener-ready mozContentEvent is sent.
|
||||
setIsReady: function () {
|
||||
if (!this._isLoaded) {
|
||||
Cu.reportError('SystemApp.setIsLoaded() should be called before setIsReady().');
|
||||
}
|
||||
|
||||
if (this._isReady) {
|
||||
Cu.reportError('SystemApp has already been declared as being ready.');
|
||||
}
|
||||
this._isReady = true;
|
||||
|
||||
// Dispatch all events being queued while the system app was still loading
|
||||
this._pendingEvents
|
||||
// Dispatch all events being queued while the system app was still not ready
|
||||
this._pendingReadyEvents
|
||||
.forEach(([type, details]) =>
|
||||
this._sendCustomEvent(type, details));
|
||||
this._pendingEvents = [];
|
||||
this._pendingReadyEvents = [];
|
||||
},
|
||||
|
||||
/*
|
||||
|
@ -62,6 +84,9 @@ var SystemAppProxy = {
|
|||
* @param details The event details.
|
||||
* @param noPending Set to true to emit this event even before the system
|
||||
* app is ready.
|
||||
* Event is always pending if the app is not loaded yet.
|
||||
*
|
||||
* @returns event? Dispatched event, or null if the event is pending.
|
||||
*/
|
||||
_sendCustomEvent: function systemApp_sendCustomEvent(type,
|
||||
details,
|
||||
|
@ -69,10 +94,22 @@ var SystemAppProxy = {
|
|||
target) {
|
||||
let content = this._frame ? this._frame.contentWindow : null;
|
||||
|
||||
// If the system app isn't loaded yet,
|
||||
// queue events until someone calls setIsLoaded
|
||||
if (!content || !this._isLoaded) {
|
||||
if (noPending) {
|
||||
this._pendingLoadedEvents.push([type, details]);
|
||||
} else {
|
||||
this._pendingReadyEvents.push([type, details]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the system app isn't ready yet,
|
||||
// queue events until someone calls setIsReady
|
||||
if (!content || (!this._isReady && !noPending)) {
|
||||
this._pendingEvents.push([type, details]);
|
||||
if (!this._isReady && !noPending) {
|
||||
this._pendingReadyEvents.push([type, details]);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -87,6 +124,10 @@ var SystemAppProxy = {
|
|||
payload = details ? Cu.cloneInto(details, content) : {};
|
||||
}
|
||||
|
||||
if ((target || content) === this._frame.contentWindow) {
|
||||
dump('XXX FIXME : Dispatch a ' + type + ': ' + details.type + "\n");
|
||||
}
|
||||
|
||||
event.initCustomEvent(type, true, false, payload);
|
||||
(target || content).dispatchEvent(event);
|
||||
|
||||
|
|
|
@ -27,10 +27,11 @@ function next() {
|
|||
// Listen for events received by the system app document
|
||||
// to ensure that we receive all of them, in an expected order and time
|
||||
var isLoaded = false;
|
||||
var isReady = false;
|
||||
var n = 0;
|
||||
function listener(event) {
|
||||
if (!isLoaded) {
|
||||
assert.ok(false, "Received event before the iframe is ready");
|
||||
assert.ok(false, "Received event before the iframe is loaded");
|
||||
return;
|
||||
}
|
||||
n++;
|
||||
|
@ -41,16 +42,34 @@ function listener(event) {
|
|||
assert.equal(event.type, "custom");
|
||||
assert.equal(event.detail.name, "second");
|
||||
|
||||
next(); // call checkEventDispatching
|
||||
next(); // call checkEventPendingBeforeLoad
|
||||
} else if (n == 3) {
|
||||
if (!isReady) {
|
||||
assert.ok(false, "Received event before the iframe is loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
assert.equal(event.type, "custom");
|
||||
assert.equal(event.detail.name, "third");
|
||||
} else if (n == 4) {
|
||||
if (!isReady) {
|
||||
assert.ok(false, "Received event before the iframe is loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
assert.equal(event.type, "mozChromeEvent");
|
||||
assert.equal(event.detail.name, "fourth");
|
||||
|
||||
next(); // call checkEventDispatching
|
||||
} else if (n == 5) {
|
||||
assert.equal(event.type, "custom");
|
||||
assert.equal(event.detail.name, "fifth");
|
||||
} else if (n === 6) {
|
||||
assert.equal(event.type, "mozChromeEvent");
|
||||
assert.equal(event.detail.name, "sixth");
|
||||
} else if (n === 7) {
|
||||
assert.equal(event.type, "custom");
|
||||
assert.equal(event.detail.name, "seventh");
|
||||
assert.equal(event.target, customEventTarget);
|
||||
|
||||
next(); // call checkEventListening();
|
||||
|
@ -72,8 +91,8 @@ var steps = [
|
|||
|
||||
function earlyEvents() {
|
||||
// Immediately try to send events
|
||||
SystemAppProxy.dispatchEvent({ name: "first" });
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "second" });
|
||||
SystemAppProxy._sendCustomEvent("mozChromeEvent", { name: "first" }, true);
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "second" }, true);
|
||||
next();
|
||||
},
|
||||
|
||||
|
@ -110,7 +129,7 @@ var steps = [
|
|||
// Declare that the iframe is now loaded.
|
||||
// That should dispatch early events
|
||||
isLoaded = true;
|
||||
SystemAppProxy.setIsReady();
|
||||
SystemAppProxy.setIsLoaded();
|
||||
assert.ok(true, "Frame declared as loaded");
|
||||
|
||||
let gotFrame = SystemAppProxy.getFrame();
|
||||
|
@ -123,13 +142,24 @@ var steps = [
|
|||
frame.setAttribute("src", "data:text/html,system app");
|
||||
},
|
||||
|
||||
function checkEventPendingBeforeLoad() {
|
||||
// Frame is loaded but not ready,
|
||||
// these events should queue before the System app is ready.
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "third" });
|
||||
SystemAppProxy.dispatchEvent({ name: "fourth" });
|
||||
|
||||
isReady = true;
|
||||
SystemAppProxy.setIsReady();
|
||||
// Once this 4th event is received, we will run checkEventDispatching
|
||||
},
|
||||
|
||||
function checkEventDispatching() {
|
||||
// Send events after the iframe is ready,
|
||||
// they should be dispatched right away
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "third" });
|
||||
SystemAppProxy.dispatchEvent({ name: "fourth" });
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "fifth" }, false, customEventTarget);
|
||||
// Once this 5th event is received, we will run checkEventListening
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "fifth" });
|
||||
SystemAppProxy.dispatchEvent({ name: "sixth" });
|
||||
SystemAppProxy._sendCustomEvent("custom", { name: "seventh" }, false, customEventTarget);
|
||||
// Once this 7th event is received, we will run checkEventListening
|
||||
},
|
||||
|
||||
function checkEventListening() {
|
||||
|
|
|
@ -38,9 +38,6 @@ function disableRadio() {
|
|||
}
|
||||
|
||||
addMessageListener('prepare-network', function(message) {
|
||||
//RIL DOM events will be pending until RIL receiveing system-message-listener-ready event.
|
||||
Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
|
||||
|
||||
connection.addEventListener('datachange', function onDataChange() {
|
||||
if (connection.data.connected) {
|
||||
connection.removeEventListener('datachange', onDataChange);
|
||||
|
|
|
@ -32,6 +32,9 @@ if (cm) {
|
|||
var SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Services.prefs.setBoolPref(SECURITY_PREF, true);
|
||||
// RIL DOM events and mozChromeEvents will be pending until
|
||||
// this observer message is sent.
|
||||
Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
|
||||
|
||||
function openWindow(aEvent) {
|
||||
var popupIframe = aEvent.detail.frameElement;
|
||||
|
|
Загрузка…
Ссылка в новой задаче