Bug 880548 - Register activities that expose the 'view' type as content handlers r=vingtetun

This commit is contained in:
Fabrice Desré 2013-08-08 15:04:03 -07:00
parent 4bdd6d2653
commit 1f7c7dc2c8
4 changed files with 175 additions and 13 deletions

View File

@ -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

View File

@ -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]);

View File

@ -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;
}
);
}
}

View File

@ -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;
},