mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 20:49:27 +00:00
Bug 715814 - Implement Web Activities: DOM Part [r=mounir]
This commit is contained in:
parent
1ef55968bc
commit
d19bb08b57
@ -477,8 +477,11 @@
|
||||
@BINPATH@/components/SystemMessageManager.js
|
||||
@BINPATH@/components/SystemMessageManager.manifest
|
||||
|
||||
@BINPATH@/components/ActivityProxy.js
|
||||
@BINPATH@/components/Activities.manifest
|
||||
@BINPATH@/components/ActivityOptions.js
|
||||
@BINPATH@/components/ActivityProxy.js
|
||||
@BINPATH@/components/ActivityRequestHandler.js
|
||||
@BINPATH@/components/ActivityWrapper.js
|
||||
|
||||
@BINPATH@/components/AppProtocolHandler.js
|
||||
@BINPATH@/components/AppProtocolHandler.manifest
|
||||
|
@ -17,6 +17,7 @@ XPIDLSRCS = nsIDOMActivity.idl \
|
||||
nsIDOMActivityRequestHandler.idl \
|
||||
nsIDOMNavigatorActivities.idl \
|
||||
nsIActivityProxy.idl \
|
||||
nsIActivityUIGlue.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
25
dom/activities/interfaces/nsIActivityUIGlue.idl
Normal file
25
dom/activities/interfaces/nsIActivityUIGlue.idl
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, function, uuid(7a16feb4-5a78-4589-9174-b728f26942e2)]
|
||||
interface nsIActivityUIGlueCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in long choice);
|
||||
};
|
||||
|
||||
/**
|
||||
* To be implemented by @mozilla.org/dom/activities/ui-glue;1
|
||||
*/
|
||||
[scriptable, uuid(8624ad73-937a-400f-9d93-39ab5449b867)]
|
||||
interface nsIActivityUIGlue : nsISupports
|
||||
{
|
||||
/**
|
||||
* @param name The name of the activity to handle (eg. "share", "pick").
|
||||
* @param activities A json blob which is an array of { "title":"...", "icon":"..." }.
|
||||
* @param onresult The callback to send the index of the choosen activity. Send -1 if no choice is made.
|
||||
*/
|
||||
void chooseActivity(in DOMString title, in jsval activities, in nsIActivityUIGlueCallback onresult);
|
||||
};
|
@ -1,2 +1,11 @@
|
||||
component {ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c5949} ActivityProxy.js
|
||||
contract @mozilla.org/dom/activities/proxy;1 {ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c5949}
|
||||
|
||||
component {5430d6f9-32d6-4924-ba39-6b6d1b093cd6} ActivityWrapper.js
|
||||
contract @mozilla.org/dom/system-messages/wrapper/activity;1 {5430d6f9-32d6-4924-ba39-6b6d1b093cd6}
|
||||
|
||||
component {9326952a-dbe3-4d81-a51f-d9c160d96d6b} ActivityRequestHandler.js
|
||||
contract @mozilla.org/dom/activities/request-handler;1 {9326952a-dbe3-4d81-a51f-d9c160d96d6b}
|
||||
|
||||
component {ee983dbb-d5ea-4c5b-be98-10a13cac9f9d} ActivityOptions.js
|
||||
contract @mozilla.org/dom/activities/options;1 {ee983dbb-d5ea-4c5b-be98-10a13cac9f9d}
|
||||
|
292
dom/activities/src/ActivitiesService.jsm
Normal file
292
dom/activities/src/ActivitiesService.jsm
Normal file
@ -0,0 +1,292 @@
|
||||
/* 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 Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
|
||||
return Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIFrameMessageManager);
|
||||
});
|
||||
|
||||
const EXPORTED_SYMBOLS = [];
|
||||
|
||||
let idbGlobal = this;
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-- ActivitiesService.jsm " + Date.now() + " " + aMsg + "\n");
|
||||
}
|
||||
|
||||
const DB_NAME = "activities";
|
||||
const DB_VERSION = 1;
|
||||
const STORE_NAME = "activities";
|
||||
|
||||
function ActivitiesDb() {
|
||||
|
||||
}
|
||||
|
||||
ActivitiesDb.prototype = {
|
||||
__proto__: IndexedDBHelper.prototype,
|
||||
|
||||
init: function actdb_init() {
|
||||
let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]
|
||||
.getService(Ci.nsIIndexedDatabaseManager);
|
||||
idbManager.initWindowless(idbGlobal);
|
||||
this.initDBHelper(DB_NAME, DB_VERSION, STORE_NAME, idbGlobal);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the initial database schema.
|
||||
*
|
||||
* The schema of records stored is as follows:
|
||||
*
|
||||
* {
|
||||
* id: String
|
||||
* manifest: String
|
||||
* name: String
|
||||
* title: String
|
||||
* icon: String
|
||||
* description: jsval
|
||||
* }
|
||||
*/
|
||||
upgradeSchema: function actdb_upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
|
||||
debug("Upgrade schema " + aOldVersion + " -> " + aNewVersion);
|
||||
let objectStore = aDb.createObjectStore(STORE_NAME, { keyPath: "id" });
|
||||
|
||||
// indexes
|
||||
objectStore.createIndex("name", "name", { unique: false });
|
||||
objectStore.createIndex("manifest", "manifest", { unique: false });
|
||||
|
||||
debug("Created object stores and indexes");
|
||||
},
|
||||
|
||||
// unique ids made of (uri, action)
|
||||
createId: function actdb_createId(aObject) {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(hasher.SHA1);
|
||||
|
||||
// add uri and action to the hash
|
||||
["manifest", "name"].forEach(function(aProp) {
|
||||
let data = converter.convertToByteArray(aObject[aProp], {});
|
||||
hasher.update(data, data.length);
|
||||
});
|
||||
|
||||
return hasher.finish(true);
|
||||
},
|
||||
|
||||
add: function actdb_add(aObject, aSuccess, aError) {
|
||||
this.newTxn("readwrite", function (txn, store) {
|
||||
let object = {
|
||||
manifest: aObject.manifest,
|
||||
name: aObject.name,
|
||||
title: aObject.title || "",
|
||||
icon: aObject.icon || "",
|
||||
description: aObject.description
|
||||
};
|
||||
object.id = this.createId(object);
|
||||
debug("Going to add " + JSON.stringify(object));
|
||||
|
||||
store.put(object);
|
||||
}.bind(this), aSuccess, aError);
|
||||
},
|
||||
|
||||
// we want to remove all activities for (manifest, name)
|
||||
remove: function actdb_remove(aObject) {
|
||||
this.newTxn("readwrite", function (txn, store) {
|
||||
let object = {
|
||||
manifest: aObject.manifest,
|
||||
name: aObject.name
|
||||
};
|
||||
debug("Going to remove " + JSON.stringify(object));
|
||||
store.delete(this.createId(object));
|
||||
}.bind(this), function() {}, function() {});
|
||||
},
|
||||
|
||||
find: function actdb_find(aObject, aSuccess, aError, aMatch) {
|
||||
debug("Looking for " + aObject.options.name);
|
||||
|
||||
this.newTxn("readonly", function (txn, store) {
|
||||
let index = store.index("name");
|
||||
let request = index.mozGetAll(aObject.options.name);
|
||||
request.onsuccess = function findSuccess(aEvent) {
|
||||
debug("Request successful. Record count: " + aEvent.target.result.length);
|
||||
if (!txn.result) {
|
||||
txn.result = {
|
||||
name: aObject.options.name,
|
||||
options: []
|
||||
};
|
||||
}
|
||||
|
||||
aEvent.target.result.forEach(function(result) {
|
||||
if (!aMatch(result))
|
||||
return;
|
||||
|
||||
txn.result.options.push({
|
||||
manifest: result.manifest,
|
||||
title: result.title,
|
||||
icon: result.icon,
|
||||
description: result.description
|
||||
});
|
||||
});
|
||||
}
|
||||
}.bind(this), aSuccess, aError);
|
||||
}
|
||||
}
|
||||
|
||||
let Activities = {
|
||||
messages: [
|
||||
// ActivityProxy.js
|
||||
"Activity:Start",
|
||||
|
||||
// ActivityRequestHandler.js
|
||||
"Activity:PostResult",
|
||||
"Activity:PostError",
|
||||
|
||||
"Activities:Register",
|
||||
"Activities:Unregister",
|
||||
],
|
||||
|
||||
init: function activities_init() {
|
||||
this.messages.forEach(function(msgName) {
|
||||
ppmm.addMessageListener(msgName, this);
|
||||
}, this);
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
|
||||
this.db = new ActivitiesDb();
|
||||
this.db.init();
|
||||
},
|
||||
|
||||
observe: function activities_observe(aSubject, aTopic, aData) {
|
||||
this.messages.forEach(function(msgName) {
|
||||
ppmm.removeMessageListener(msgName, this);
|
||||
}, this);
|
||||
ppmm = null;
|
||||
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts an activity by doing:
|
||||
* - finds a list of matching activities.
|
||||
* - calls the UI glue to get the user choice.
|
||||
* - fire an system message of type "activity" to this app, sending the
|
||||
* activity data as a payload.
|
||||
*/
|
||||
startActivity: function activities_startActivity(aMsg) {
|
||||
debug("StartActivity: " + JSON.stringify(aMsg));
|
||||
|
||||
let successCb = function successCb(aResults) {
|
||||
debug(JSON.stringify(aResults));
|
||||
|
||||
// We have no matching activity registered, let's fire an error.
|
||||
if (aResults.length === 0) {
|
||||
ppmm.sendAsyncMessage("Activity:FireError", {
|
||||
"id": aMsg.id,
|
||||
"error": "NO_PROVIDER"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
function getActivityChoice(aChoice) {
|
||||
debug("Activity choice: " + aChoice);
|
||||
|
||||
// The user has cancelled the choice, fire an error.
|
||||
if (aChoice === -1) {
|
||||
ppmm.sendAsyncMessage("Activity:FireError", {
|
||||
"id": aMsg.id,
|
||||
"error": "USER_ABORT"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let sysmm = Cc["@mozilla.org/system-message-internal;1"]
|
||||
.getService(Ci.nsISystemMessagesInternal);
|
||||
if (!sysmm) {
|
||||
// System message is not present, what should we do?
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Sending system message...");
|
||||
let result = aResults.options[aChoice];
|
||||
sysmm.sendMessage("activity", {
|
||||
"id": aMsg.id,
|
||||
"payload": aMsg.options
|
||||
}, Services.io.newURI(result.manifest, null, null));
|
||||
|
||||
if (!result.description.returnValue) {
|
||||
ppmm.sendAsyncMessage("Activity:FireSuccess", {
|
||||
"id": aMsg.id,
|
||||
"result": null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"]
|
||||
.createInstance(Ci.nsIActivityUIGlue);
|
||||
glue.chooseActivity(aResults.name, aResults.options, getActivityChoice);
|
||||
};
|
||||
|
||||
let errorCb = function errorCb(aError) {
|
||||
// Something unexpected happened. Should we send an error back?
|
||||
debug("Error in startActivity: " + aError + "\n");
|
||||
};
|
||||
|
||||
let matchFunc = function matchFunc(aResult) {
|
||||
// Bug 773383: arrays of strings / regexp.
|
||||
for (let prop in aResult.description.filters) {
|
||||
if (aMsg.options.data[prop] !== aResult.description.filters[prop]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
this.db.find(aMsg, successCb, errorCb, matchFunc);
|
||||
},
|
||||
|
||||
receiveMessage: function activities_receiveMessage(aMessage) {
|
||||
let mm = aMessage.target.QueryInterface(Ci.nsIFrameMessageManager);
|
||||
let msg = aMessage.json;
|
||||
switch(aMessage.name) {
|
||||
case "Activity:Start":
|
||||
this.startActivity(msg);
|
||||
break;
|
||||
|
||||
case "Activity:PostResult":
|
||||
ppmm.sendAsyncMessage("Activity:FireSuccess", msg);
|
||||
break;
|
||||
case "Activity:PostError":
|
||||
ppmm.sendAsyncMessage("Activity:FireError", msg);
|
||||
break;
|
||||
|
||||
case "Activities:Register":
|
||||
this.db.add(msg, function onSuccess(aEvent) {
|
||||
mm.sendAsyncMessage("Activities:Register:OK", msg);
|
||||
},
|
||||
function onError(aEvent) {
|
||||
msg.error = "REGISTER_ERROR";
|
||||
mm.sendAsyncMessage("Activities:Register:KO", msg);
|
||||
});
|
||||
break;
|
||||
case "Activities:Unregister":
|
||||
this.db.remove(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Activities.init();
|
56
dom/activities/src/ActivityOptions.js
Normal file
56
dom/activities/src/ActivityOptions.js
Normal file
@ -0,0 +1,56 @@
|
||||
/* 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 Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-- ActivityOptions.js " + Date.now() + " : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* nsIDOMMozActivityOptions implementation.
|
||||
*/
|
||||
|
||||
function ActivityOptions() {
|
||||
debug("ActivityOptions");
|
||||
this.wrappedJSObject = this;
|
||||
|
||||
// When a system message of type 'activity' is emitted, it forces the
|
||||
// creation of an ActivityWrapper which in turns replace the default
|
||||
// system message callback. The newly created wrapper then create a
|
||||
// nsIDOMActivityRequestHandler object and fills up the properties of
|
||||
// this object as well as the properties of the nsIDOMActivityOptions
|
||||
// object contains by the request handler.
|
||||
this._name = null;
|
||||
this._data = null;
|
||||
}
|
||||
|
||||
ActivityOptions.prototype = {
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
classID: Components.ID("{ee983dbb-d5ea-4c5b-be98-10a13cac9f9d}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozActivityOptions]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: Components.ID("{ee983dbb-d5ea-4c5b-be98-10a13cac9f9d}"),
|
||||
contractID: "@mozilla.org/dom/activities/options;1",
|
||||
interfaces: [Ci.nsIDOMMozActivityOptions],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "Activity Options"
|
||||
})
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityOptions]);
|
76
dom/activities/src/ActivityRequestHandler.js
Normal file
76
dom/activities/src/ActivityRequestHandler.js
Normal file
@ -0,0 +1,76 @@
|
||||
/* 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;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
|
||||
return Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIFrameMessageManager)
|
||||
.QueryInterface(Ci.nsISyncMessageSender);
|
||||
});
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-- ActivityRequestHandler.js " + Date.now() + " : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* nsIDOMMozActivityRequestHandler implementation.
|
||||
*/
|
||||
|
||||
function ActivityRequestHandler() {
|
||||
debug("ActivityRequestHandler");
|
||||
this.wrappedJSObject = this;
|
||||
|
||||
// When a system message of type 'activity' is emitted, it forces the
|
||||
// creation of an ActivityWrapper which in turns replace the default
|
||||
// system message callback. The newly created wrapper then create a
|
||||
// nsIDOMActivityRequestHandler object and fills up the properties of
|
||||
// this object as well as the properties of the nsIDOMActivityOptions
|
||||
// object contains by the request handler.
|
||||
this._id = null;
|
||||
this._options = Cc["@mozilla.org/dom/activities/options;1"]
|
||||
.createInstance(Ci.nsIDOMMozActivityOptions);
|
||||
}
|
||||
|
||||
ActivityRequestHandler.prototype = {
|
||||
get source() {
|
||||
return this._options;
|
||||
},
|
||||
|
||||
postResult: function arh_postResult(aResult) {
|
||||
cpmm.sendAsyncMessage("Activity:PostResult", {
|
||||
"id": this._id,
|
||||
"result": aResult
|
||||
});
|
||||
},
|
||||
|
||||
postError: function arh_postError(aError) {
|
||||
cpmm.sendAsyncMessage("Activity:PostError", {
|
||||
"id": this._id,
|
||||
"error": aError
|
||||
});
|
||||
},
|
||||
|
||||
classID: Components.ID("{9326952a-dbe3-4d81-a51f-d9c160d96d6b}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIDOMMozActivityRequestHandler
|
||||
]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: Components.ID("{9326952a-dbe3-4d81-a51f-d9c160d96d6b}"),
|
||||
contractID: "@mozilla.org/dom/activities/request-handler;1",
|
||||
interfaces: [Ci.nsIDOMMozActivityRequestHandler],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "Activity Request Handler"
|
||||
})
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityRequestHandler]);
|
45
dom/activities/src/ActivityWrapper.js
Normal file
45
dom/activities/src/ActivityWrapper.js
Normal file
@ -0,0 +1,45 @@
|
||||
/* 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;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-- ActivityWrapper.js " + Date.now() + " : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* nsISystemMessagesWrapper implementation. Will return a
|
||||
* nsIDOMMozActivityRequestHandler
|
||||
*/
|
||||
function ActivityWrapper() {
|
||||
debug("ActivityWrapper");
|
||||
}
|
||||
|
||||
ActivityWrapper.prototype = {
|
||||
wrapMessage: function wrapMessage(aMessage) {
|
||||
debug("Wrapping " + JSON.stringify(aMessage));
|
||||
let handler = Cc["@mozilla.org/dom/activities/request-handler;1"]
|
||||
.createInstance(Ci.nsIDOMMozActivityRequestHandler);
|
||||
handler.wrappedJSObject._id = aMessage.id;
|
||||
|
||||
// options is an nsIDOMActivityOptions object.
|
||||
var options = handler.wrappedJSObject._options;
|
||||
options.wrappedJSObject._name = aMessage.payload.name;
|
||||
options.wrappedJSObject._data = aMessage.payload.data;
|
||||
|
||||
return handler;
|
||||
},
|
||||
|
||||
classID: Components.ID("{5430d6f9-32d6-4924-ba39-6b6d1b093cd6}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesWrapper])
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityWrapper]);
|
||||
|
@ -26,9 +26,16 @@ EXPORTS_mozilla/dom = \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
ActivityOptions.js \
|
||||
ActivityProxy.js \
|
||||
ActivityRequestHandler.js \
|
||||
ActivityWrapper.js \
|
||||
Activities.manifest \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
ActivitiesService.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -14,6 +14,7 @@ let EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "DOMApplicationManifest"];
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
||||
|
||||
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
|
||||
|
||||
@ -27,6 +28,10 @@ XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
|
||||
.getService(Ci.nsIFrameMessageManager);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIFrameMessageManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "msgmgr", function() {
|
||||
return Cc["@mozilla.org/system-message-internal;1"]
|
||||
.getService(Ci.nsISystemMessagesInternal);
|
||||
@ -67,7 +72,7 @@ let DOMApplicationRegistry = {
|
||||
this.webapps = aData;
|
||||
for (let id in this.webapps) {
|
||||
#ifdef MOZ_SYS_MSG
|
||||
this._registerSystemMessagesForId(id);
|
||||
this._processManifestForId(id);
|
||||
#endif
|
||||
if (!this.webapps[id].localId) {
|
||||
this.webapps[id].localId = this._nextLocalId();
|
||||
@ -99,10 +104,51 @@ let DOMApplicationRegistry = {
|
||||
}
|
||||
},
|
||||
|
||||
_registerSystemMessagesForId: function(aId) {
|
||||
_registerActivities: function(aManifest, aApp) {
|
||||
if (!aManifest.activities) {
|
||||
return;
|
||||
}
|
||||
|
||||
let manifest = new DOMApplicationManifest(aManifest, aApp.origin);
|
||||
for (let activity in aManifest.activities) {
|
||||
let description = aManifest.activities[activity];
|
||||
let json = {
|
||||
"manifest": aApp.manifestURL,
|
||||
"name": activity,
|
||||
"title": manifest.name,
|
||||
"icon": manifest.iconURLForSize(128),
|
||||
"description": description
|
||||
}
|
||||
cpmm.sendAsyncMessage("Activities:Register", json);
|
||||
|
||||
let launchPath =
|
||||
Services.io.newURI(manifest.fullLaunchPath(description.href), null, null);
|
||||
let manifestURL = Services.io.newURI(aApp.manifestURL, null, null);
|
||||
msgmgr.registerPage("activity", launchPath, manifestURL);
|
||||
}
|
||||
},
|
||||
|
||||
_unregisterActivities: function(aManifest, aApp) {
|
||||
if (!aManifest.activities) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let activity in aManifest.activities) {
|
||||
let description = aManifest.activities[activity];
|
||||
let json = {
|
||||
"manifest": aApp.manifestURL,
|
||||
"name": activity
|
||||
}
|
||||
cpmm.sendAsyncMessage("Activities:Unregister", json);
|
||||
}
|
||||
},
|
||||
|
||||
_processManifestForId: function(aId) {
|
||||
let app = this.webapps[aId];
|
||||
this._readManifests([{ id: aId }], (function registerManifest(aResult) {
|
||||
this._registerSystemMessages(aResult[0].manifest, app);
|
||||
let manifest = aResult[0].manifest;
|
||||
this._registerSystemMessages(manifest, app);
|
||||
this._registerActivities(manifest, app);
|
||||
}).bind(this));
|
||||
},
|
||||
#endif
|
||||
@ -489,26 +535,36 @@ let DOMApplicationRegistry = {
|
||||
let found = false;
|
||||
for (let id in this.webapps) {
|
||||
let app = this.webapps[id];
|
||||
if (app.origin == aData.origin) {
|
||||
found = true;
|
||||
let appNote = JSON.stringify(this._cloneAppObject(app));
|
||||
appNote.id = id;
|
||||
|
||||
delete this.webapps[id];
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
this._saveApps((function() {
|
||||
ppmm.sendAsyncMessage("Webapps:Uninstall:Return:OK", aData);
|
||||
Services.obs.notifyObservers(this, "webapps-sync-uninstall", appNote);
|
||||
}).bind(this));
|
||||
if (app.origin != aData.origin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
let appNote = JSON.stringify(this._cloneAppObject(app));
|
||||
appNote.id = id;
|
||||
|
||||
this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
|
||||
#ifdef MOZ_SYS_MSG
|
||||
this._unregisterActivities(aResult[0].manifest, app);
|
||||
#endif
|
||||
}).bind(this));
|
||||
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch (e) {}
|
||||
|
||||
delete this.webapps[id];
|
||||
|
||||
this._saveApps((function() {
|
||||
ppmm.sendAsyncMessage("Webapps:Uninstall:Return:OK", aData);
|
||||
Services.obs.notifyObservers(this, "webapps-sync-uninstall", appNote);
|
||||
}).bind(this));
|
||||
}
|
||||
if (!found)
|
||||
|
||||
if (!found) {
|
||||
ppmm.sendAsyncMessage("Webapps:Uninstall:Return:KO", aData);
|
||||
}
|
||||
},
|
||||
|
||||
getSelf: function(aData) {
|
||||
|
@ -45,6 +45,27 @@ function SystemMessageManager() {
|
||||
SystemMessageManager.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_dispatchMessage: function sysMessMgr_dispatchMessage(aType, aHandler, aMessage) {
|
||||
// We get a json blob, but in some cases we want another kind of object
|
||||
// to be dispatched.
|
||||
// To do so, we check if we have a with a contract ID of
|
||||
// "@mozilla.org/dom/system-messages/wrapper/TYPE;1" component implementing
|
||||
// nsISystemMessageWrapper.
|
||||
debug("Dispatching " + JSON.stringify(aMessage) + "\n");
|
||||
let contractID = "@mozilla.org/dom/system-messages/wrapper/" + aType + ";1";
|
||||
|
||||
if (contractID in Cc) {
|
||||
debug(contractID + " is registered, creating an instance");
|
||||
let wrapper = Cc[contractID].createInstance(Ci.nsISystemMessagesWrapper);
|
||||
if (wrapper) {
|
||||
aMessage = wrapper.wrapMessage(aMessage);
|
||||
debug("wrapped = " + aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
aHandler.handleMessage(aMessage);
|
||||
},
|
||||
|
||||
mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
|
||||
debug("setMessage handler for [" + aType + "] " + aHandler);
|
||||
if (!aType) {
|
||||
@ -68,10 +89,11 @@ SystemMessageManager.prototype = {
|
||||
let thread = Services.tm.mainThread;
|
||||
let pending = this._pendings[aType];
|
||||
this._pendings[aType] = [];
|
||||
let self = this;
|
||||
pending.forEach(function dispatch_pending(aPending) {
|
||||
thread.dispatch({
|
||||
run: function run() {
|
||||
aHandler.handleMessage(aPending);
|
||||
self._dispatchMessage(aType, aHandler, aPending);
|
||||
}
|
||||
}, Ci.nsIEventTarget.DISPATCH_NORMAL);
|
||||
});
|
||||
@ -139,7 +161,7 @@ SystemMessageManager.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this._handlers[msg.type].handleMessage(msg.msg);
|
||||
this._dispatchMessage(msg.type, this._handlers[msg.type], msg.msg);
|
||||
},
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer implementation.
|
||||
|
@ -27,3 +27,13 @@ interface nsISystemMessagesInternal : nsISupports
|
||||
*/
|
||||
void registerPage(in DOMString type, in nsIURI pageURI, in nsIURI manifestURI);
|
||||
};
|
||||
|
||||
[scriptable, uuid(b43c74ec-1b64-49fb-b552-aadd9d827eec)]
|
||||
interface nsISystemMessagesWrapper: nsISupports
|
||||
{
|
||||
/*
|
||||
* Wrap a message and gives back any kind of object.
|
||||
* @param message The json blob to wrap.
|
||||
*/
|
||||
jsval wrapMessage(in jsval message);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user