diff --git a/b2g/components/B2GComponents.manifest b/b2g/components/B2GComponents.manifest index a9cf8b11dd6..87f78260702 100644 --- a/b2g/components/B2GComponents.manifest +++ b/b2g/components/B2GComponents.manifest @@ -40,7 +40,8 @@ category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1 # ContentHandler.js component {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} ContentHandler.js -contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} +contract @mozilla.org/b2g/activities-content-handler;1 {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} +category app-startup ContentHandler service,@mozilla.org/b2g/activities-content-handler;1 # PaymentGlue.js component {8b83eabc-7929-47f4-8b48-4dea8d887e4b} PaymentGlue.js diff --git a/b2g/components/ContentHandler.js b/b2g/components/ContentHandler.js index ec37a51d1c9..38b25fb33f3 100644 --- a/b2g/components/ContentHandler.js +++ b/b2g/components/ContentHandler.js @@ -18,22 +18,28 @@ XPCOMUtils.defineLazyGetter(this, "cpmm", function() { .getService(Ci.nsIMessageSender); }); -function log(aMsg) { - let msg = "ContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg); - Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService) - .logStringMessage(msg); - dump(msg + "\n"); +function debug(aMsg) { + //dump("--*-- ContentHandler: " + aMsg + "\n"); } const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; -function ContentHandler() { + +let ActivityContentFactory = { + createInstance: function createInstance(outer, iid) { + if (outer != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } + return new ActivityContentHandler().QueryInterface(iid); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]) } -ContentHandler.prototype = { - handleContent: function handleContent(aMimetype, aContext, aRequest) { - if (aMimetype != PDF_CONTENT_TYPE) - throw NS_ERROR_WONT_HANDLE_CONTENT; +function ActivityContentHandler() { +} +ActivityContentHandler.prototype = { + handleContent: function handleContent(aMimetype, aContext, aRequest) { if (!(aRequest instanceof Ci.nsIChannel)) throw NS_ERROR_WONT_HANDLE_CONTENT; @@ -46,8 +52,96 @@ ContentHandler.prototype = { aRequest.cancel(Cr.NS_BINDING_ABORTED); }, - classID: Components.ID("{d18d0216-d50c-11e1-ba54-efb18d0ef0ac}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]) +} + +function ContentHandler() { + this.classIdMap = {}; +} + +ContentHandler.prototype = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == "app-startup") { + // We only want to register these from content processes. + let appInfo = Cc["@mozilla.org/xre/app-info;1"]; + if (appInfo.getService(Ci.nsIXULRuntime) + .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + return; + } + } + + cpmm.addMessageListener("Activities:RegisterContentTypes", this); + cpmm.addMessageListener("Activities:UnregisterContentTypes", this); + cpmm.sendAsyncMessage("Activities:GetContentTypes", { }); + }, + + /** + * Do the component registration for a content type. + * We only need to register one component per content type, even if several + * apps provide it, so we keep track of the number of providers for each + * content type. + */ + registerContentHandler: function registerContentHandler(aContentType) { + debug("Registering " + aContentType); + + // We already have a provider for this content type, just increase the + // tracking count. + if (this.classIdMap[aContentType]) { + this.classIdMap[aContentType].count++; + return; + } + + let contractID = "@mozilla.org/uriloader/content-handler;1?type=" + + aContentType; + let uuidGen = Cc["@mozilla.org/uuid-generator;1"] + .getService(Ci.nsIUUIDGenerator); + let id = Components.ID(uuidGen.generateUUID().toString()); + this.classIdMap[aContentType] = { count: 1, id: id }; + let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + cr.registerFactory(Components.ID(id), "Activity Content Handler", contractID, + ActivityContentFactory); + }, + + /** + * Do the component unregistration for a content type. + */ + unregisterContentHandler: function registerContentHandler(aContentType) { + debug("Unregistering " + aContentType); + + let record = this.classIdMap[aContentType]; + if (!record) { + return; + } + + // Bail out if we still have providers left for this content type. + if (--record.count > 0) { + return; + } + + let contractID = "@mozilla.org/uriloader/content-handler;1?type=" + + aContentType; + let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + cr.unregisterFactory(record.id, ActivityContentFactory); + delete this.classIdMap[aContentType] + }, + + receiveMessage: function(aMessage) { + let data = aMessage.data; + + switch (aMessage.name) { + case "Activities:RegisterContentTypes": + data.contentTypes.forEach(this.registerContentHandler, this); + break; + case "Activities:UnregisterContentTypes": + data.contentTypes.forEach(this.unregisterContentHandler, this); + break; + } + }, + + classID: Components.ID("{d18d0216-d50c-11e1-ba54-efb18d0ef0ac}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler, + Ci.nsIObserver, + Ci.nsISupportsWeakReference]) }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentHandler]); diff --git a/dom/activities/src/ActivitiesService.jsm b/dom/activities/src/ActivitiesService.jsm index 955e0081b23..c3688b7f9cb 100644 --- a/dom/activities/src/ActivitiesService.jsm +++ b/dom/activities/src/ActivitiesService.jsm @@ -17,6 +17,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageBroadcaster"); +XPCOMUtils.defineLazyServiceGetter(this, "NetUtil", + "@mozilla.org/network/util;1", + "nsINetUtil"); + this.EXPORTED_SYMBOLS = []; let idbGlobal = this; @@ -158,6 +162,7 @@ let Activities = { "Activities:Register", "Activities:Unregister", + "Activities:GetContentTypes" ], init: function activities_init() { @@ -311,9 +316,18 @@ let Activities = { break; case "Activities:Register": + let self = this; this.db.add(msg, function onSuccess(aEvent) { mm.sendAsyncMessage("Activities:Register:OK", null); + let res = []; + msg.forEach(function(aActivity) { + self.updateContentTypeList(aActivity, res); + }); + if (res.length) { + ppmm.broadcastAsyncMessage("Activities:RegisterContentTypes", + { contentTypes: res }); + } }, function onError(aEvent) { msg.error = "REGISTER_ERROR"; @@ -322,8 +336,60 @@ let Activities = { break; case "Activities:Unregister": this.db.remove(msg); + let res = []; + msg.forEach(function(aActivity) { + this.updateContentTypeList(aActivity, res); + }, this); + if (res.length) { + ppmm.broadcastAsyncMessage("Activities:UnregisterContentTypes", + { contentTypes: res }); + } + break; + case "Activities:GetContentTypes": + this.sendContentTypes(mm); break; } + }, + + updateContentTypeList: function updateContentTypeList(aActivity, aResult) { + // Bail out if this is not a "view" activity. + if (aActivity.name != "view") { + return; + } + + let types = aActivity.description.filters.type; + if (typeof types == "string") { + types = [types]; + } + + // Check that this is a real content type and sanitize it. + types.forEach(function(aContentType) { + let hadCharset = { }; + let charset = { }; + let contentType = + NetUtil.parseContentType(aContentType, charset, hadCharset); + if (contentType) { + aResult.push(contentType); + } + }); + }, + + sendContentTypes: function sendContentTypes(aMm) { + let res = []; + let self = this; + this.db.find({ options: { name: "view" } }, + function() { // Success callback. + if (res.length) { + aMm.sendAsyncMessage("Activities:RegisterContentTypes", + { contentTypes: res }); + } + }, + null, // Error callback. + function(aActivity) { // Matching callback. + self.updateContentTypeList(aActivity, res) + return false; + } + ); } } diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index 7f1f66099f6..143b8c6abaf 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -688,7 +688,8 @@ this.DOMApplicationRegistry = { for (let activity in root.activities) { let description = root.activities[activity]; activitiesToUnregister.push({ "manifest": aApp.manifestURL, - "name": activity }); + "name": activity, + "description": description }); } return activitiesToUnregister; },