Bug 1165841 - Part 5: remove listener when window is destroyed. r=dimi
--- a/dom/nfc/NfcContentHelper.js
+++ b/dom/nfc/NfcContentHelper.js
@@ -189,16 +189,22 @@ NfcContentHelper.prototype = {
updateDebug();
};
}
this.eventListeners[tabId] = listener;
cpmm.sendAsyncMessage("NFC:AddEventListener", { tabId: tabId });
},
+ removeEventListener: function removeEventListener(tabId) {
+ delete this.eventListeners[tabId];
+
+ cpmm.sendAsyncMessage("NFC:RemoveEventListener", { tabId: tabId });
+ },
+
registerTargetForPeerReady: function registerTargetForPeerReady(appId) {
cpmm.sendAsyncMessage("NFC:RegisterPeerReadyTarget", { appId: appId });
},
unregisterTargetForPeerReady: function unregisterTargetForPeerReady(appId) {
cpmm.sendAsyncMessage("NFC:UnregisterPeerReadyTarget", { appId: appId });
},
--- a/dom/nfc/gonk/Nfc.js
+++ b/dom/nfc/gonk/Nfc.js
@@ -52,16 +52,17 @@ updateDebug();
const NFC_CONTRACTID = "@mozilla.org/nfc;1";
const NFC_CID =
Components.ID("{2ff24790-5e74-11e1-b86c-0800200c9a66}");
const NFC_IPC_MSG_ENTRIES = [
{ permission: null,
messages: ["NFC:AddEventListener",
+ "NFC:RemoveEventListener",
"NFC:QueryInfo",
"NFC:CallDefaultFoundHandler",
"NFC:CallDefaultLostHandler"] },
{ permission: "nfc",
messages: ["NFC:ReadNDEF",
"NFC:WriteNDEF",
"NFC:MakeReadOnly",
@@ -251,22 +252,26 @@ XPCOMUtils.defineLazyGetter(this, "gMess
}
this.eventListeners[id] = target;
},
removeEventListener: function removeEventListener(target) {
for (let id in this.eventListeners) {
if (target == this.eventListeners[id]) {
- delete this.eventListeners[id];
+ this.removeEventListenerById(id);
break;
}
}
},
+ removeEventListenerById: function removeEventListenerById(id) {
+ delete this.eventListeners[id];
+ },
+
checkP2PRegistration: function checkP2PRegistration(message) {
let target = this.peerTargets[message.data.appId];
let sessionToken = SessionHelper.getCurrentP2PToken();
let isValid = (sessionToken != null) && (target != null);
let respMsg = { requestId: message.data.requestId };
if (!isValid) {
respMsg.errorMsg = this.nfc.getErrorMessage(NFC.NFC_GECKO_ERROR_P2P_REG_INVALID);
}
@@ -380,16 +385,19 @@ XPCOMUtils.defineLazyGetter(this, "gMess
switch (message.name) {
case "NFC:SetFocusApp":
this.setFocusApp(message.data.tabId, message.data.isFocus);
return null;
case "NFC:AddEventListener":
this.addEventListener(message.target, message.data.tabId);
return null;
+ case "NFC:RemoveEventListener":
+ this.removeEventListenerById(message.data.tabId);
+ return null;
case "NFC:RegisterPeerReadyTarget":
this.registerPeerReadyTarget(message.target, message.data.appId);
return null;
case "NFC:UnregisterPeerReadyTarget":
this.unregisterPeerReadyTarget(message.data.appId);
return null;
case "NFC:CheckP2PRegistration":
this.checkP2PRegistration(message);
--- a/dom/nfc/nsINfcContentHelper.idl
+++ b/dom/nfc/nsINfcContentHelper.idl
@@ -119,17 +119,17 @@ interface nsINfcRequestCallback : nsISup
interface nsINfcBrowserAPI : nsISupports
{
const int32_t SYSTEM_APP_ID = -1;
void setFocusApp(in uint64_t tabId,
in boolean isFocus);
};
-[scriptable, uuid(f098c114-b21f-43f5-9f53-0c22b4f194eb)]
+[scriptable, uuid(75f0c8c0-2e5a-491f-a75d-4f3849c4feec)]
interface nsINfcContentHelper : nsISupports
{
/**
* Read current NDEF data on the tag.
*
* @param sessionToken
* Current token
*
@@ -232,16 +232,24 @@ interface nsINfcContentHelper : nsISuppo
* @param listener
* An instance of the nsINfcEventListener.
* @param tabId
* The tab ID of the listener.
*/
void addEventListener(in nsINfcEventListener listener, in uint64_t tabId);
/**
+ * Remove event listener.
+ *
+ * @param tabId
+ * The tabId provided in addEventListener.
+ */
+ void removeEventListener(in uint64_t tabId);
+
+ /**
* Register the given application id with parent process
*
* @param appId
* Application ID to be registered
*/
void registerTargetForPeerReady(in unsigned long appId);
/**
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -340,31 +340,39 @@ function MozNFCImpl() {
this.eventService = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
}
MozNFCImpl.prototype = {
_nfcContentHelper: null,
window: null,
_tabId: null,
+ _innerWindowId: null,
_rfState: null,
_contentObj: null,
nfcPeer: null,
nfcTag: null,
eventService: null,
init: function init(aWindow) {
debug("MozNFCImpl init called");
this.window = aWindow;
+ let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ this._innerWindowId = util.currentInnerWindowID;
+
this.defineEventHandlerGetterSetter("ontagfound");
this.defineEventHandlerGetterSetter("ontaglost");
this.defineEventHandlerGetterSetter("onpeerready");
this.defineEventHandlerGetterSetter("onpeerfound");
this.defineEventHandlerGetterSetter("onpeerlost");
+ Services.obs.addObserver(this, "inner-window-destroyed",
+ /* weak-ref */ false);
+
if (this._nfcContentHelper) {
this._tabId = this.getTabId(aWindow);
this._nfcContentHelper.addEventListener(this, this._tabId);
this._rfState = this._nfcContentHelper.queryRFState();
}
},
getTabId: function getTabId(aWindow) {
@@ -436,16 +444,29 @@ MozNFCImpl.prototype = {
this._nfcContentHelper.changeRFState(RFState.IDLE, callback);
return callback.promise;
},
get enabled() {
return this._rfState != RFState.IDLE;
},
+ observe: function observe(subject, topic, data) {
+ if (topic !== "inner-window-destroyed") {
+ return;
+ }
+
+ let wId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
+ if (wId != this._innerWindowId) {
+ return;
+ }
+
+ this._nfcContentHelper.removeEventListener(this._tabId);
+ },
+
defineEventHandlerGetterSetter: function defineEventHandlerGetterSetter(name) {
Object.defineProperty(this, name, {
get: function get() {
return this.__DOM_IMPL__.getEventHandler(name);
},
set: function set(handler) {
this.__DOM_IMPL__.setEventHandler(name, handler);
}
@@ -694,17 +715,18 @@ MozNFCImpl.prototype = {
hasDeadWrapper: function hasDeadWrapper() {
return Cu.isDeadWrapper(this.window) || Cu.isDeadWrapper(this.__DOM_IMPL__);
},
classID: Components.ID("{6ff2b290-2573-11e3-8224-0800200c9a66}"),
contractID: "@mozilla.org/nfc/manager;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIDOMGlobalPropertyInitializer,
- Ci.nsINfcEventListener]),
+ Ci.nsINfcEventListener,
+ Ci.nsIObserver]),
};
function NFCSendFileWrapper() {
}
NFCSendFileWrapper.prototype = {
// nsISystemMessagesWrapper implementation.
wrapMessage: function wrapMessage(aMessage, aWindow) {
let peerImpl = new MozNFCPeerImpl(aWindow, aMessage.sessionToken);