зеркало из https://github.com/mozilla/gecko-dev.git
Bug 755245 - Implement System Message Handler : Part 3, DOM implementation [r=vingtetun,mounir]
This commit is contained in:
Родитель
c5aa869164
Коммит
62b3e61301
|
@ -50,6 +50,8 @@
|
|||
#include "BluetoothManager.h"
|
||||
#endif
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
|
||||
// This should not be in the namespace.
|
||||
DOMCI_DATA(Navigator, mozilla::dom::Navigator)
|
||||
|
||||
|
@ -109,6 +111,7 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
|
|||
#ifdef MOZ_B2G_BT
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth)
|
||||
#endif
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorSystemMessages)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -172,6 +175,13 @@ Navigator::Invalidate()
|
|||
mBluetooth = nsnull;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_SYS_MSG
|
||||
if (mMessagesManager) {
|
||||
mMessagesManager = nsnull;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
nsPIDOMWindow *
|
||||
|
@ -1249,6 +1259,67 @@ Navigator::GetMozBluetooth(nsIDOMBluetoothManager** aBluetooth)
|
|||
}
|
||||
#endif //MOZ_B2G_BT
|
||||
|
||||
//*****************************************************************************
|
||||
// nsNavigator::nsIDOMNavigatorSystemMessages
|
||||
//*****************************************************************************
|
||||
#ifdef MOZ_SYS_MSG
|
||||
NS_IMETHODIMP
|
||||
Navigator::EnsureMessagesManager()
|
||||
{
|
||||
if (mMessagesManager) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMNavigatorSystemMessages> messageManager =
|
||||
do_CreateInstance("@mozilla.org/system-message-manager;1", &rv);
|
||||
|
||||
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
|
||||
do_QueryInterface(messageManager);
|
||||
NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE);
|
||||
|
||||
// We don't do anything with the return value.
|
||||
jsval prop_val = JSVAL_VOID;
|
||||
rv = gpi->Init(window, &prop_val);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mMessagesManager = messageManager.forget();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
Navigator::MozHasPendingMessage(const nsAString& aType, bool *aResult)
|
||||
{
|
||||
#ifdef MOZ_SYS_MSG
|
||||
*aResult = false;
|
||||
nsresult rv = EnsureMessagesManager();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return mMessagesManager->MozHasPendingMessage(aType, aResult);
|
||||
#else
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Navigator::MozSetMessageHandler(const nsAString& aType,
|
||||
nsIDOMSystemMessageCallback *aCallback)
|
||||
{
|
||||
#ifdef MOZ_SYS_MSG
|
||||
nsresult rv = EnsureMessagesManager();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return mMessagesManager->MozSetMessageHandler(aType, aCallback);
|
||||
#else
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t
|
||||
Navigator::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
{
|
||||
|
|
|
@ -38,6 +38,8 @@ class nsIDOMTelephony;
|
|||
#include "nsIDOMNavigatorBluetooth.h"
|
||||
#endif
|
||||
|
||||
#include "nsIDOMNavigatorSystemMessages.h"
|
||||
|
||||
//*****************************************************************************
|
||||
// Navigator: Script "navigator" object
|
||||
//*****************************************************************************
|
||||
|
@ -79,7 +81,7 @@ class Navigator : public nsIDOMNavigator
|
|||
#ifdef MOZ_B2G_BT
|
||||
, public nsIDOMNavigatorBluetooth
|
||||
#endif
|
||||
|
||||
, public nsIDOMNavigatorSystemMessages
|
||||
{
|
||||
public:
|
||||
Navigator(nsPIDOMWindow *aInnerWindow);
|
||||
|
@ -104,6 +106,7 @@ public:
|
|||
#ifdef MOZ_B2G_BT
|
||||
NS_DECL_NSIDOMNAVIGATORBLUETOOTH
|
||||
#endif
|
||||
NS_DECL_NSIDOMNAVIGATORSYSTEMMESSAGES
|
||||
|
||||
static void Init();
|
||||
|
||||
|
@ -126,6 +129,11 @@ public:
|
|||
*/
|
||||
void OnNavigation();
|
||||
|
||||
#ifdef MOZ_SYS_MSG
|
||||
// Helper to initialize mMessagesManager.
|
||||
nsresult EnsureMessagesManager();
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool IsSmsAllowed() const;
|
||||
bool IsSmsSupported() const;
|
||||
|
@ -145,6 +153,7 @@ private:
|
|||
#ifdef MOZ_B2G_BT
|
||||
nsCOMPtr<nsIDOMBluetoothManager> mBluetooth;
|
||||
#endif
|
||||
nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
|
||||
nsWeakPtr mWindow;
|
||||
};
|
||||
|
||||
|
|
|
@ -522,6 +522,8 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
|
|||
#include "BluetoothAdapter.h"
|
||||
#endif
|
||||
|
||||
#include "nsIDOMNavigatorSystemMessages.h"
|
||||
|
||||
#include "DOMError.h"
|
||||
#include "DOMRequest.h"
|
||||
#include "nsIOpenWindowEventDetail.h"
|
||||
|
@ -2483,6 +2485,7 @@ nsDOMClassInfo::Init()
|
|||
#ifdef MOZ_B2G_BT
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth)
|
||||
#endif
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorSystemMessages)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
|
||||
|
|
|
@ -13,4 +13,10 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
PARALLEL_DIRS = interfaces
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
SystemMessageManager.js \
|
||||
SystemMessageInternal.js \
|
||||
SystemMessageManager.manifest \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
/* 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");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
|
||||
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
|
||||
});
|
||||
|
||||
// Limit the number of pending messages for a given page.
|
||||
let kMaxPendingMessages;
|
||||
try {
|
||||
kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
|
||||
} catch(e) {
|
||||
// getIntPref throws when the pref is not set.
|
||||
kMaxPendingMessages = 5;
|
||||
}
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
// Implementation of the component used by internal users.
|
||||
|
||||
function SystemMessageInternal() {
|
||||
// The set of pages registered by installed apps. We keep the
|
||||
// list of pending messages for each page here also.
|
||||
this._pages = [];
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
ppmm.addMessageListener("SystemMessageManager:GetPending", this);
|
||||
}
|
||||
|
||||
SystemMessageInternal.prototype = {
|
||||
sendMessage: function sendMessage(aType, aMessage, aManifestURI) {
|
||||
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
|
||||
ppmm.sendAsyncMessage("SystemMessageManager:Message" , { type: aType,
|
||||
msg: aMessage,
|
||||
manifest: aManifestURI.spec });
|
||||
|
||||
// Queue the message for pages that registered an handler for this type.
|
||||
this._pages.forEach(function sendMess_openPage(aPage) {
|
||||
if (aPage.type != aType || aPage.manifest != aManifestURI.spec) {
|
||||
return;
|
||||
}
|
||||
|
||||
aPage.pending.push(aMessage);
|
||||
if (aPage.pending.length > kMaxPendingMessages) {
|
||||
aPage.pending.splice(0, 1);
|
||||
}
|
||||
|
||||
// We don't need to send the full object to observers.
|
||||
let page = { uri: aPage.uri, manifest: aPage.manifest };
|
||||
debug("Asking to open " + JSON.stringify(page));
|
||||
Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
|
||||
}.bind(this))
|
||||
},
|
||||
|
||||
registerPage: function registerPage(aType, aPageURI, aManifestURI) {
|
||||
if (!aPageURI || !aManifestURI) {
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
this._pages.push({ type: aType,
|
||||
uri: aPageURI.spec,
|
||||
manifest: aManifestURI.spec,
|
||||
pending: [] });
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
debug("received SystemMessageManager:GetPending " + aMessage.json.type + " for " + aMessage.json.uri + " @ " + aMessage.json.manifest);
|
||||
// This is a sync call, use to return the pending message for a page.
|
||||
let msg = aMessage.json;
|
||||
debug(JSON.stringify(msg));
|
||||
|
||||
// Find the right page.
|
||||
let page = null;
|
||||
this._pages.some(function(aPage) {
|
||||
if (aPage.uri == msg.uri &&
|
||||
aPage.type == msg.type &&
|
||||
aPage.manifest == msg.manifest) {
|
||||
page = aPage;
|
||||
}
|
||||
return page !== null;
|
||||
});
|
||||
|
||||
if (!page) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let pending = page.pending;
|
||||
// Clear the pending queue for this page.
|
||||
// This is ok since we'll store pending events in SystemMessageManager.js
|
||||
page.pending = [];
|
||||
|
||||
return pending;
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "xpcom-shutdown") {
|
||||
ppmm.removeMessageListener("SystemMessageManager:GetPending", this);
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
ppmm = null;
|
||||
this._pages = null;
|
||||
}
|
||||
},
|
||||
|
||||
classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver])
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageInternal]);
|
|
@ -0,0 +1,172 @@
|
|||
/* 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");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
|
||||
return Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIFrameMessageManager)
|
||||
.QueryInterface(Ci.nsISyncMessageSender);
|
||||
});
|
||||
|
||||
// Limit the number of pending messages for a given type.
|
||||
let kMaxPendingMessages;
|
||||
try {
|
||||
kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
|
||||
} catch(e) {
|
||||
// getIntPref throws when the pref is not set.
|
||||
kMaxPendingMessages = 5;
|
||||
}
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
// Implementation of the DOM API for system messages
|
||||
|
||||
function SystemMessageManager() {
|
||||
// Message handlers for this page.
|
||||
// We can have only one handler per message type.
|
||||
this._handlers = {};
|
||||
|
||||
// Pending messages for this page, keyed by message type.
|
||||
this._pendings = {};
|
||||
}
|
||||
|
||||
SystemMessageManager.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
|
||||
debug("setMessage handler for [" + aType + "] " + aHandler);
|
||||
if (!aType) {
|
||||
// Just bail out if we have no type.
|
||||
return;
|
||||
}
|
||||
|
||||
let handlers = this._handlers;
|
||||
if (!aHandler) {
|
||||
// Setting the handler to null means we don't want to receive messages
|
||||
// of this type anymore.
|
||||
delete handlers[aType];
|
||||
return;
|
||||
}
|
||||
|
||||
// Last registered handler wins.
|
||||
handlers[aType] = aHandler;
|
||||
|
||||
// If we have pending messages, send them asynchronously.
|
||||
if (this._getPendingMessages(aType, true)) {
|
||||
let thread = Services.tm.mainThread;
|
||||
let pending = this._pendings[aType];
|
||||
this._pendings[aType] = [];
|
||||
pending.forEach(function dispatch_pending(aPending) {
|
||||
thread.dispatch({
|
||||
run: function run() {
|
||||
aHandler.handleMessage(aPending);
|
||||
}
|
||||
}, Ci.nsIEventTarget.DISPATCH_NORMAL);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_getPendingMessages: function sysMessMgr_getPendingMessages(aType, aForceUpdate) {
|
||||
debug("hasPendingMessage " + aType);
|
||||
let pendings = this._pendings;
|
||||
|
||||
// If we have a handler for this type, we can't have any pending message.
|
||||
// If called from setMessageHandler, we still want to update the pending
|
||||
// queue to deliver existing messages.
|
||||
if (aType in this._handlers && !aForceUpdate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a sync message to the parent to check if we have a pending message
|
||||
// for this type.
|
||||
let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending",
|
||||
{ type: aType,
|
||||
uri: this._uri,
|
||||
manifest: this._manifest })[0];
|
||||
if (!messages) {
|
||||
// No new pending messages, but the queue may not be empty yet.
|
||||
return pendings[aType] && pendings[aType].length != 0;
|
||||
}
|
||||
|
||||
if (!pendings[aType]) {
|
||||
pendings[aType] = [];
|
||||
}
|
||||
|
||||
// Doing that instead of pending.concat() to avoid array copy.
|
||||
messages.forEach(function hpm_addPendings(aMessage) {
|
||||
pendings[aType].push(aMessage);
|
||||
if (pendings[aType].length > kMaxPendingMessages) {
|
||||
pendings[aType].splice(0, 1);
|
||||
}
|
||||
});
|
||||
|
||||
return pendings[aType].length != 0;
|
||||
},
|
||||
|
||||
mozHasPendingMessage: function sysMessMgr_hasPendingMessage(aType) {
|
||||
return this._getPendingMessages(aType, false);
|
||||
},
|
||||
|
||||
uninit: function sysMessMgr_uninit() {
|
||||
this._handlers = null;
|
||||
this._pendings = null;
|
||||
},
|
||||
|
||||
receiveMessage: function sysMessMgr_receiveMessage(aMessage) {
|
||||
debug("receiveMessage " + aMessage.name + " - " +
|
||||
aMessage.json.type + " for " + aMessage.json.manifest +
|
||||
" (" + this._manifest + ")");
|
||||
|
||||
let msg = aMessage.json;
|
||||
if (msg.manifest != this._manifest)
|
||||
return;
|
||||
|
||||
// Bail out if we have no handlers registered for this type.
|
||||
if (!(msg.type in this._handlers)) {
|
||||
debug("No handler for this type");
|
||||
return;
|
||||
}
|
||||
|
||||
this._handlers[msg.type].handleMessage(msg.msg);
|
||||
},
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer implementation.
|
||||
init: function sysMessMgr_init(aWindow) {
|
||||
debug("init");
|
||||
this.initHelper(aWindow, ["SystemMessageManager:Message"]);
|
||||
this._uri = aWindow.document.nodePrincipal.URI.spec;
|
||||
let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
|
||||
// Get the manifest url is this is an installed app.
|
||||
this._manifest = null;
|
||||
let app = utils.getApp();
|
||||
if (app)
|
||||
this._manifest = app.manifestURL;
|
||||
},
|
||||
|
||||
classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMNavigatorSystemMessages,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
|
||||
contractID: "@mozilla.org/system-message-manager;1",
|
||||
interfaces: [Ci.nsIDOMNavigatorSystemMessages],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "System Messages"})
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageManager]);
|
|
@ -0,0 +1,5 @@
|
|||
component {bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2} SystemMessageManager.js
|
||||
contract @mozilla.org/system-message-manager;1 {bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}
|
||||
|
||||
component {70589ca5-91ac-4b9e-b839-d6a88167d714} SystemMessageInternal.js
|
||||
contract @mozilla.org/system-message-internal;1 {70589ca5-91ac-4b9e-b839-d6a88167d714}
|
|
@ -15,6 +15,7 @@ include $(topsrcdir)/dom/dom-config.mk
|
|||
|
||||
XPIDLSRCS = \
|
||||
nsIDOMNavigatorSystemMessages.idl \
|
||||
nsISystemMessagesInternal.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* 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 "domstubs.idl"
|
||||
|
||||
interface nsIURI;
|
||||
|
||||
// Implemented by the contract id @mozilla.org/system-message-internal;1
|
||||
|
||||
[scriptable, uuid(fdc1ba03-5d8f-4de9-894a-333c7a136c5f)]
|
||||
interface nsISystemMessagesInternal : nsISupports
|
||||
{
|
||||
/*
|
||||
* Allow any internal user to broadcast a message of a given type.
|
||||
* @param type The type of the message to be sent.
|
||||
* @param message The message payload.
|
||||
* @param manifestURI The webapp's manifest URI.
|
||||
*/
|
||||
void sendMessage(in DOMString type, in jsval message, in nsIURI manifestURI);
|
||||
|
||||
/*
|
||||
* Registration of a page that wants to be notified of a message type.
|
||||
* @param type The message type.
|
||||
* @param pageURI The URI of the page that will be opened.
|
||||
* @param manifestURI The webapp's manifest URI.
|
||||
*/
|
||||
void registerPage(in DOMString type, in nsIURI pageURI, in nsIURI manifestURI);
|
||||
};
|
Загрузка…
Ссылка в новой задаче