Bug 1165841 - Part 5: remove listener when window is destroyed. r=dimi
authorYoshi Huang <allstars.chh@mozilla.com>
Wed, 20 May 2015 15:01:16 +0800
changeset 266175 ad7a84b5768273dc21dba02ec3e2a1405f61f10a
parent 266174 863ea6c9461e84c8ed3f7e1c33866c9b6ab04a6e
child 266176 a8d3ebe7e47538e8ffa37c1adf4d3dba32d7a140
push id2231
push usermichael.l.comella@gmail.com
push dateFri, 22 May 2015 20:04:59 +0000
reviewersdimi
bugs1165841
milestone41.0a1
Bug 1165841 - Part 5: remove listener when window is destroyed. r=dimi
dom/nfc/NfcContentHelper.js
dom/nfc/gonk/Nfc.js
dom/nfc/nsINfcContentHelper.idl
dom/nfc/nsNfc.js
--- 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);