Bug 1150683 - Implement nsIPushNotificationService. r=dougt

---
 b2g/installer/package-manifest.in     |   2 +-
 browser/installer/package-manifest.in |   2 +-
 dom/push/Push.manifest                |  11 +-
 dom/push/PushNotificationService.js   |  81 +++++++++
 dom/push/PushService.jsm              | 324 ++++++++++++++++++++--------------
 dom/push/PushServiceLauncher.js       |  50 ------
 dom/push/moz.build                    |   2 +-
 7 files changed, 285 insertions(+), 187 deletions(-)
 create mode 100644 dom/push/PushNotificationService.js
 delete mode 100644 dom/push/PushServiceLauncher.js
This commit is contained in:
Kit Cambridge 2015-04-21 20:10:50 +02:00
parent 6855cac604
commit 86e4e52d97
7 changed files with 285 additions and 187 deletions

View File

@ -630,7 +630,7 @@
@RESPATH@/components/AppsService.manifest @RESPATH@/components/AppsService.manifest
@RESPATH@/components/Push.js @RESPATH@/components/Push.js
@RESPATH@/components/Push.manifest @RESPATH@/components/Push.manifest
@RESPATH@/components/PushServiceLauncher.js @RESPATH@/components/PushNotificationService.js
@RESPATH@/components/InterAppComm.manifest @RESPATH@/components/InterAppComm.manifest
@RESPATH@/components/InterAppCommService.js @RESPATH@/components/InterAppCommService.js

View File

@ -557,7 +557,7 @@
@RESPATH@/components/AlarmsManager.manifest @RESPATH@/components/AlarmsManager.manifest
@RESPATH@/components/Push.js @RESPATH@/components/Push.js
@RESPATH@/components/Push.manifest @RESPATH@/components/Push.manifest
@RESPATH@/components/PushServiceLauncher.js @RESPATH@/components/PushNotificationService.js
@RESPATH@/components/SlowScriptDebug.manifest @RESPATH@/components/SlowScriptDebug.manifest
@RESPATH@/components/SlowScriptDebug.js @RESPATH@/components/SlowScriptDebug.js

View File

@ -5,7 +5,10 @@ contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
component {CA86B665-BEDA-4212-8D0F-5C9F65270B58} Push.js component {CA86B665-BEDA-4212-8D0F-5C9F65270B58} Push.js
contract @mozilla.org/push/PushSubscription;1 {CA86B665-BEDA-4212-8D0F-5C9F65270B58} contract @mozilla.org/push/PushSubscription;1 {CA86B665-BEDA-4212-8D0F-5C9F65270B58}
# Component to initialize PushService on startup. # XPCOM component; initializes the PushService on startup.
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js component {32028e38-903b-4a64-a180-5857eb4cb3dd} PushNotificationService.js
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} contract @mozilla.org/push/NotificationService;1 {32028e38-903b-4a64-a180-5857eb4cb3dd}
category app-startup PushServiceLauncher @mozilla.org/push/ServiceLauncher;1 category app-startup PushNotificationService @mozilla.org/push/NotificationService;1
component {66a87970-6dc9-46e0-ac61-adb4a13791de} PushNotificationService.js
contract @mozilla.org/push/ObserverNotification;1 {66a87970-6dc9-46e0-ac61-adb4a13791de}

View File

@ -0,0 +1,81 @@
/* 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 Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
let isParent = Cc["@mozilla.org/xre/runtime;1"]
.getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
XPCOMUtils.defineLazyGetter(this, "PushService", function() {
// Lazily initialize the PushService on
// `sessionstore-windows-restored` or first use.
const {PushService} = Cu.import("resource://gre/modules/PushService.jsm", {});
if (isParent) {
PushService.init();
}
return PushService;
});
this.PushNotificationService = function PushNotificationService() {};
PushNotificationService.prototype = {
classID: Components.ID("{32028e38-903b-4a64-a180-5857eb4cb3dd}"),
contractID: "@mozilla.org/push/NotificationService;1",
_xpcom_factory: XPCOMUtils.generateSingletonFactory(PushNotificationService),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference,
Ci.nsIPushNotificationService]),
register: function register(scope, pageURL) {
return PushService._register({scope, pageURL});
},
unregister: function unregister(scope) {
return PushService._unregister({scope});
},
registration: function registration(scope) {
return PushService._registration({scope});
},
observe: function observe(subject, topic, data) {
switch (topic) {
case "app-startup":
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
break;
case "sessionstore-windows-restored":
Services.obs.removeObserver(this, "sessionstore-windows-restored");
if (isParent) {
PushService.init();
}
break;
}
}
};
this.PushObserverNotification = function PushObserverNotification() {};
PushObserverNotification.prototype = {
classID: Components.ID("{66a87970-6dc9-46e0-ac61-adb4a13791de}"),
contractID: "@mozilla.org/push/ObserverNotification;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushObserverNotification])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
PushNotificationService,
PushObserverNotification
]);

View File

@ -294,6 +294,7 @@ this.PushService = {
*/ */
case "xpcom-shutdown": case "xpcom-shutdown":
this.uninit(); this.uninit();
break;
case "network-active-changed": /* On B2G. */ case "network-active-changed": /* On B2G. */
case "network:offline-status-changed": /* On desktop. */ case "network:offline-status-changed": /* On desktop. */
// In case of network-active-changed, always disconnect existing // In case of network-active-changed, always disconnect existing
@ -348,9 +349,12 @@ this.PushService = {
.deferred.reject({status: 0, error: "TimeoutError"}); .deferred.reject({status: 0, error: "TimeoutError"});
delete this._pendingRequests[channelID]; delete this._pendingRequests[channelID];
for (let i = this._requestQueue.length - 1; i >= 0; --i) for (let i = this._requestQueue.length - 1; i >= 0; --i) {
if (this._requestQueue[i].channelID == channelID) let [, data] = this._requestQueue[i];
if (data && data.channelID == channelID) {
this._requestQueue.splice(i, 1); this._requestQueue.splice(i, 1);
}
}
} }
} }
@ -493,6 +497,9 @@ this.PushService = {
init: function() { init: function() {
debug("init()"); debug("init()");
if (this._started) {
return;
}
var globalMM = Cc["@mozilla.org/globalmessagemanager;1"] var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIFrameScriptLoader); .getService(Ci.nsIFrameScriptLoader);
@ -564,6 +571,7 @@ this.PushService = {
this._waitingForPong = false; this._waitingForPong = false;
this._stopAlarm(); this._stopAlarm();
this._cancelPendingRequests();
}, },
uninit: function() { uninit: function() {
@ -603,6 +611,7 @@ this.PushService = {
this._requestTimeoutTimer.cancel(); this._requestTimeoutTimer.cancel();
} }
this._started = false;
debug("shutdown complete!"); debug("shutdown complete!");
}, },
@ -880,6 +889,10 @@ this.PushService = {
_startListeningIfChannelsPresent: function() { _startListeningIfChannelsPresent: function() {
// Check to see if we need to do anything. // Check to see if we need to do anything.
if (this._requestQueue.length > 0) {
this._beginWSSetup();
return;
}
this._db.getAllChannelIDs(function(channelIDs) { this._db.getAllChannelIDs(function(channelIDs) {
if (channelIDs.length > 0) { if (channelIDs.length > 0) {
this._beginWSSetup(); this._beginWSSetup();
@ -1163,11 +1176,9 @@ this.PushService = {
debug("sendRequest() " + action); debug("sendRequest() " + action);
if (typeof data.channelID !== "string") { if (typeof data.channelID !== "string") {
debug("Received non-string channelID"); debug("Received non-string channelID");
return Promise.reject("Received non-string channelID"); return Promise.reject({error: "Received non-string channelID"});
} }
let deferred = Promise.defer();
if (Object.keys(this._pendingRequests).length == 0) { if (Object.keys(this._pendingRequests).length == 0) {
// start the timer since we now have at least one request // start the timer since we now have at least one request
if (!this._requestTimeoutTimer) if (!this._requestTimeoutTimer)
@ -1178,8 +1189,18 @@ this.PushService = {
Ci.nsITimer.TYPE_REPEATING_SLACK); Ci.nsITimer.TYPE_REPEATING_SLACK);
} }
this._pendingRequests[data.channelID] = { deferred: deferred, let deferred;
ctime: Date.now() }; let request = this._pendingRequests[data.channelID];
if (request) {
// If a request is already pending for this channel ID, assume it's a
// retry. Use the existing deferred, but update the send time and re-send
// the request.
deferred = request.deferred;
} else {
deferred = Promise.defer();
request = this._pendingRequests[data.channelID] = {deferred};
}
request.ctime = Date.now();
this._send(action, data); this._send(action, data);
return deferred.promise; return deferred.promise;
@ -1201,6 +1222,11 @@ this.PushService = {
} }
if (this._currentState != STATE_READY) { if (this._currentState != STATE_READY) {
if (!this._started) {
// The component hasn't been initialized yet. Return early; init()
// will dequeue all pending requests.
return;
}
if (!this._ws) { if (!this._ws) {
// This will end up calling processNextRequestInQueue(). // This will end up calling processNextRequestInQueue().
this._beginWSSetup(); this._beginWSSetup();
@ -1269,52 +1295,49 @@ this.PushService = {
// registration. // registration.
_notifyAllAppsRegister: function() { _notifyAllAppsRegister: function() {
debug("notifyAllAppsRegister()"); debug("notifyAllAppsRegister()");
let deferred = Promise.defer(); return new Promise((resolve, reject) => {
// records are objects describing the registration as stored in IndexedDB.
// records are objects describing the registration as stored in IndexedDB. this._db.getAllChannelIDs(records => {
function wakeupRegisteredApps(records) { let scopes = new Set();
// Pages to be notified. for (let record of records) {
// wakeupTable[scope] -> [ pageURL ] scopes.add(record.scope);
let wakeupTable = {}; }
for (let i = 0; i < records.length; i++) { let globalMM = Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager);
let record = records[i]; for (let scope of scopes) {
if (!(record.scope in wakeupTable)) // Notify XPCOM observers.
wakeupTable[record.scope] = []; Services.obs.notifyObservers(
null,
wakeupTable[record.scope].push(record.pageURL); "push-subscription-change",
} scope
);
// TODO -- test needed. E10s support needed. // TODO -- test needed. E10s support needed.
globalMM.broadcastAsyncMessage('pushsubscriptionchanged', scope);
let globalMM = Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager); }
for (let scope in wakeupTable) { resolve();
wakeupTable[scope].forEach(function(pageURL) { }, reject);
globalMM.broadcastAsyncMessage('pushsubscriptionchanged', aPushRecord.scope); });
});
}
deferred.resolve();
}
this._db.getAllChannelIDs(wakeupRegisteredApps, deferred.reject);
return deferred.promise;
}, },
_notifyApp: function(aPushRecord) { _notifyApp: function(aPushRecord) {
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.scope) { if (!aPushRecord || !aPushRecord.scope) {
debug("notifyApp() something is undefined. Dropping notification: " debug("notifyApp() something is undefined. Dropping notification: "
+ JSON.stringify(aPushRecord) ); + JSON.stringify(aPushRecord) );
return; return;
} }
debug("notifyApp() " + aPushRecord.pageURL + debug("notifyApp() " + aPushRecord.scope);
" " + aPushRecord.scope);
let pageURI = Services.io.newURI(aPushRecord.pageURL, null, null);
let scopeURI = Services.io.newURI(aPushRecord.scope, null, null); let scopeURI = Services.io.newURI(aPushRecord.scope, null, null);
let message = { // Notify XPCOM observers.
pushEndpoint: aPushRecord.pushEndpoint, let notification = Cc["@mozilla.org/push/ObserverNotification;1"]
version: aPushRecord.version .createInstance(Ci.nsIPushObserverNotification);
}; notification.pushEndpoint = aPushRecord.pushEndpoint;
notification.version = aPushRecord.version;
notification.data = "";
Services.obs.notifyObservers(
notification,
"push-notification",
aPushRecord.scope
);
// If permission has been revoked, trash the message. // If permission has been revoked, trash the message.
if(Services.perms.testExactPermission(scopeURI, "push") != Ci.nsIPermissionManager.ALLOW_ACTION) { if(Services.perms.testExactPermission(scopeURI, "push") != Ci.nsIPermissionManager.ALLOW_ACTION) {
@ -1363,24 +1386,38 @@ this.PushService = {
* Called on message from the child process. aPageRecord is an object sent by * Called on message from the child process. aPageRecord is an object sent by
* navigator.push, identifying the sending page and other fields. * navigator.push, identifying the sending page and other fields.
*/ */
_registerWithServer: function(channelID, aPageRecord) {
debug("registerWithServer()");
_registerWithServer: function(aPageRecord, aMessageManager) { return this._sendRequest("register", {channelID: channelID})
.then(
this._onRegisterSuccess.bind(this, aPageRecord, channelID),
this._onRegisterError.bind(this)
);
},
_generateID: function() {
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"] let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator); .getService(Ci.nsIUUIDGenerator);
// generateUUID() gives a UUID surrounded by {...}, slice them off. // generateUUID() gives a UUID surrounded by {...}, slice them off.
let channelID = uuidGenerator.generateUUID().toString().slice(1, -1); return uuidGenerator.generateUUID().toString().slice(1, -1);
},
this._sendRequest("register", {channelID: channelID}) _register: function(aPageRecord) {
.then( let recordPromise = new Promise((resolve, reject) =>
this._onRegisterSuccess.bind(this, aPageRecord, channelID), this._db.getByScope(aPageRecord.scope, resolve, reject));
this._onRegisterError.bind(this, aPageRecord, aMessageManager)
) return recordPromise.then(
.then( pushRecord => {
function(message) { if (pushRecord == null) {
aMessageManager.sendAsyncMessage("PushService:Register:OK", message); let channelID = this._generateID();
}, return this._registerWithServer(channelID, aPageRecord);
function(message) { }
aMessageManager.sendAsyncMessage("PushService:Register:KO", message); return pushRecord;
},
error => {
debug("getByScope failed");
throw "Database error";
} }
); );
}, },
@ -1388,17 +1425,20 @@ this.PushService = {
register: function(aPageRecord, aMessageManager) { register: function(aPageRecord, aMessageManager) {
debug("register(): " + JSON.stringify(aPageRecord)); debug("register(): " + JSON.stringify(aPageRecord));
this._db.getByScope(aPageRecord.scope, this._register(aPageRecord).then(
function(aPageRecord, aMessageManager, pushRecord) { function(aPageRecord, aMessageManager, pushRecord) {
if (pushRecord == null) { let message = {
this._registerWithServer(aPageRecord, aMessageManager); requestID: aPageRecord.requestID,
} pushEndpoint: pushRecord.pushEndpoint
else { };
this._onRegistrationSuccess(aPageRecord, aMessageManager, pushRecord); aMessageManager.sendAsyncMessage("PushService:Register:OK", message);
}
}.bind(this, aPageRecord, aMessageManager), }.bind(this, aPageRecord, aMessageManager),
function () { function(error) {
debug("getByScope failed"); let message = {
requestID: aPageRecord.requestID,
error
};
aMessageManager.sendAsyncMessage("PushService:Register:KO", message);
} }
); );
}, },
@ -1409,19 +1449,15 @@ this.PushService = {
*/ */
_onRegisterSuccess: function(aPageRecord, generatedChannelID, data) { _onRegisterSuccess: function(aPageRecord, generatedChannelID, data) {
debug("_onRegisterSuccess()"); debug("_onRegisterSuccess()");
let deferred = Promise.defer();
let message = { requestID: aPageRecord.requestID };
if (typeof data.channelID !== "string") { if (typeof data.channelID !== "string") {
debug("Invalid channelID " + message); debug("Invalid channelID " + data.channelID);
message["error"] = "Invalid channelID received"; throw "Invalid channelID received";
throw message;
} }
else if (data.channelID != generatedChannelID) { else if (data.channelID != generatedChannelID) {
debug("Server replied with different channelID " + data.channelID + debug("Server replied with different channelID " + data.channelID +
" than what UA generated " + generatedChannelID); " than what UA generated " + generatedChannelID);
message["error"] = "Server sent 200 status code but different channelID"; throw "Server sent 200 status code but different channelID";
throw message;
} }
try { try {
@ -1429,8 +1465,7 @@ this.PushService = {
} }
catch (e) { catch (e) {
debug("Invalid pushEndpoint " + data.pushEndpoint); debug("Invalid pushEndpoint " + data.pushEndpoint);
message["error"] = "Invalid pushEndpoint " + data.pushEndpoint; throw "Invalid pushEndpoint " + data.pushEndpoint;
throw message;
} }
let record = { let record = {
@ -1443,33 +1478,30 @@ this.PushService = {
debug("scope in _onRegisterSuccess: " + aPageRecord.scope) debug("scope in _onRegisterSuccess: " + aPageRecord.scope)
this._updatePushRecord(record) return this._updatePushRecord(record)
.then( .then(
function() { function() {
message["pushEndpoint"] = data.pushEndpoint; return record;
deferred.resolve(message);
}, },
function(error) { function(error) {
// Unable to save. // Unable to save.
this._send("unregister", {channelID: record.channelID}); this._send("unregister", {channelID: record.channelID});
message["error"] = error; throw error;
deferred.reject(message);
}.bind(this) }.bind(this)
); );
return deferred.promise;
}, },
/** /**
* Exceptions thrown in _onRegisterError are caught by the promise obtained * Exceptions thrown in _onRegisterError are caught by the promise obtained
* from _sendRequest, causing the promise to be rejected instead. * from _sendRequest, causing the promise to be rejected instead.
*/ */
_onRegisterError: function(aPageRecord, aMessageManager, reply) { _onRegisterError: function(reply) {
debug("_onRegisterError()"); debug("_onRegisterError()");
if (!reply.error) { if (!reply.error) {
debug("Called without valid error message!"); debug("Called without valid error message!");
throw "Registration error";
} }
throw { requestID: aPageRecord.requestID, error: reply.error }; throw reply.error;
}, },
/** /**
@ -1496,78 +1528,99 @@ this.PushService = {
* messages from the server, and have the client acknowledge. On a server, * messages from the server, and have the client acknowledge. On a server,
* data is cheap, reliable notification is not. * data is cheap, reliable notification is not.
*/ */
unregister: function(aPageRecord, aMessageManager) { _unregister: function(aPageRecord) {
debug("unregister() " + JSON.stringify(aPageRecord)); debug("unregisterWithServer()");
let deferred = Promise.defer();
let fail = function(error) { let fail = function(error) {
debug("unregister() fail() error " + error); debug("unregister() fail() error " + error);
let message = {requestID: aPageRecord.requestID, error: error}; deferred.reject(error);
aMessageManager.sendAsyncMessage("PushService:Unregister:KO", message); };
if (!aPageRecord.scope) {
fail("NotFoundError");
return deferred.promise;
} }
this._db.getByPushEndpoint(aPageRecord.pushEndpoint, function(record) { this._db.getByScope(aPageRecord.scope, function(record) {
// If the endpoint didn't exist, let's just fail. // If the endpoint didn't exist, let's just fail.
if (record === undefined) { if (record === undefined) {
fail("NotFoundError"); fail("NotFoundError");
return; return;
} }
// Non-owner tried to unregister, say success, but don't do anything.
if (record.scope !== aPageRecord.scope) {
aMessageManager.sendAsyncMessage("PushService:Unregister:OK", {
requestID: aPageRecord.requestID,
pushEndpoint: aPageRecord.pushEndpoint
});
return;
}
this._db.delete(record.channelID, function() { this._db.delete(record.channelID, function() {
// Let's be nice to the server and try to inform it, but we don't care // Let's be nice to the server and try to inform it, but we don't care
// about the reply. // about the reply.
this._send("unregister", {channelID: record.channelID}); this._send("unregister", {channelID: record.channelID});
deferred.resolve();
}.bind(this), fail);
}.bind(this), fail);
return deferred.promise;
},
unregister: function(aPageRecord, aMessageManager) {
debug("unregister() " + JSON.stringify(aPageRecord));
this._unregister(aPageRecord).then(
() => {
aMessageManager.sendAsyncMessage("PushService:Unregister:OK", { aMessageManager.sendAsyncMessage("PushService:Unregister:OK", {
requestID: aPageRecord.requestID, requestID: aPageRecord.requestID,
pushEndpoint: aPageRecord.pushEndpoint pushEndpoint: aPageRecord.pushEndpoint
}); });
}.bind(this), fail); },
}.bind(this), fail); error => {
aMessageManager.sendAsyncMessage("PushService:Unregister:KO", {
requestID: aPageRecord.requestID,
error
});
}
);
}, },
/** /**
* Called on message from the child process * Called on message from the child process
*/ */
_registration: function(aPageRecord) {
return new Promise((resolve, reject) => {
if (!aPageRecord.scope) {
reject("Database error");
return;
}
this._db.getByScope(aPageRecord.scope,
pushRecord => {
let registration = null;
if (pushRecord) {
registration = {
pushEndpoint: pushRecord.pushEndpoint,
version: pushRecord.version
};
}
resolve(registration);
},
() => reject("Database error")
);
});
},
registration: function(aPageRecord, aMessageManager) { registration: function(aPageRecord, aMessageManager) {
debug("registration()"); debug("registration()");
this._db.getByScope(aPageRecord.scope,
this._onRegistrationSuccess.bind(this, aPageRecord, aMessageManager),
this._onRegistrationError.bind(this, aPageRecord, aMessageManager));
},
_onRegistrationSuccess: function(aPageRecord, return this._registration(aPageRecord).then(
aMessageManager, registration => {
pushRecord) { aMessageManager.sendAsyncMessage("PushService:Registration:OK", {
requestID: aPageRecord.requestID,
registration
let registration = null; });
},
if (pushRecord) { error => {
registration = { aMessageManager.sendAsyncMessage("PushService:Registration:KO", {
pushEndpoint: pushRecord.pushEndpoint, requestID: aPageRecord.requestID,
version: pushRecord.version error
}; });
} }
);
aMessageManager.sendAsyncMessage("PushService:Registration:OK", {
requestID: aPageRecord.requestID,
registration: registration
});
},
_onRegistrationError: function(aPageRecord, aMessageManager) {
aMessageManager.sendAsyncMessage("PushService:Registration:KO", {
requestID: aPageRecord.requestID,
error: "Database error"
});
}, },
// begin Push protocol handshake // begin Push protocol handshake
@ -1730,6 +1783,17 @@ this.PushService = {
} }
}, },
/**
* Rejects all pending requests with errors.
*/
_cancelPendingRequests: function() {
for (let channelID in this._pendingRequests) {
let request = this._pendingRequests[channelID];
delete this._pendingRequests[channelID];
request.deferred.reject({status: 0, error: "CancelledError"});
}
},
/** /**
* This method should be called only if the device is on a mobile network! * This method should be called only if the device is on a mobile network!
*/ */
@ -1904,4 +1968,4 @@ this.PushService = {
".mcc" + ("00" + networkInfo.mcc).slice(-3) + ".3gppnetwork.org"; ".mcc" + ("00" + networkInfo.mcc).slice(-3) + ".3gppnetwork.org";
queryDNSForDomain(netidAddress, callback); queryDNSForDomain(netidAddress, callback);
} }
} };

View File

@ -1,50 +0,0 @@
/* 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 Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function PushServiceLauncher() {
};
PushServiceLauncher.prototype = {
classID: Components.ID("{4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}"),
contractID: "@mozilla.org/push/ServiceLauncher;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
observe: function observe(subject, topic, data) {
switch (topic) {
case "app-startup":
Services.obs.addObserver(this, "final-ui-startup", true);
break;
case "final-ui-startup":
Services.obs.removeObserver(this, "final-ui-startup");
if (!Services.prefs.getBoolPref("dom.push.enabled")) {
return;
}
let isParent = Cc["@mozilla.org/xre/runtime;1"]
.getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
if (isParent) {
Cu.import("resource://gre/modules/PushService.jsm");
PushService.init();
}
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PushServiceLauncher]);

View File

@ -6,7 +6,7 @@
EXTRA_COMPONENTS += [ EXTRA_COMPONENTS += [
'Push.js', 'Push.js',
'Push.manifest', 'Push.manifest',
'PushServiceLauncher.js', 'PushNotificationService.js',
] ]
EXTRA_JS_MODULES += [ EXTRA_JS_MODULES += [