Bug 1114433 - location.reload() leaves behind dangling gUM permission prompt. r=felipe, a=sledru
authorFlorian Quèze <florian@queze.net>
Fri, 16 Jan 2015 22:20:46 +0100
changeset 249371 510873b2ee88d630a11dd142369bf5a26aaaea4b
parent 249370 2a8e74988711045e680fb66c7ffaa20c2236a6c9
child 249372 62321380a4c3c14fa507814cb397e18520764efa
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe, sledru
bugs1114433
milestone37.0a2
Bug 1114433 - location.reload() leaves behind dangling gUM permission prompt. r=felipe, a=sledru
browser/modules/ContentWebRTC.jsm
browser/modules/webrtcUI.jsm
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -22,23 +22,31 @@ this.ContentWebRTC = {
       return;
 
     this._initialized = true;
     Services.obs.addObserver(handleRequest, "getUserMedia:request", false);
     Services.obs.addObserver(updateIndicators, "recording-device-events", false);
     Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false);
   },
 
+  // Called only for 'unload' to remove pending gUM prompts in reloaded frames.
+  handleEvent: function(aEvent) {
+    let contentWindow = aEvent.target.defaultView;
+    let mm = getMessageManagerForWindow(contentWindow);
+    for (let key of contentWindow.pendingGetUserMediaRequests.keys())
+      mm.sendAsyncMessage("webrtc:CancelRequest", key);
+  },
+
   receiveMessage: function(aMessage) {
     switch (aMessage.name) {
       case "webrtc:Allow":
         let callID = aMessage.data.callID;
         let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID);
         let devices = contentWindow.pendingGetUserMediaRequests.get(callID);
-        contentWindow.pendingGetUserMediaRequests.delete(callID);
+        forgetRequest(contentWindow, callID);
 
         let allowedDevices = Cc["@mozilla.org/supports-array;1"]
                                .createInstance(Ci.nsISupportsArray);
         for (let deviceIndex of aMessage.data.devices)
            allowedDevices.AppendElement(devices[deviceIndex]);
 
         Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", callID);
         break;
@@ -107,18 +115,20 @@ function prompt(aContentWindow, aWindowI
   if (audioDevices.length)
     requestTypes.push("Microphone");
 
   if (!requestTypes.length) {
     denyRequest({callID: aCallID}, "NotFoundError");
     return;
   }
 
-  if (!aContentWindow.pendingGetUserMediaRequests)
+  if (!aContentWindow.pendingGetUserMediaRequests) {
     aContentWindow.pendingGetUserMediaRequests = new Map();
+    aContentWindow.addEventListener("unload", ContentWebRTC);
+  }
   aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices);
 
   let request = {
     callID: aCallID,
     windowID: aWindowID,
     documentURI: aContentWindow.document.documentURI,
     secure: aSecure,
     requestTypes: requestTypes,
@@ -138,19 +148,27 @@ function denyRequest(aData, aError) {
     msg.data = aError;
   }
   Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aData.callID);
 
   if (!aData.windowID)
     return;
   let contentWindow = Services.wm.getOuterWindowWithId(aData.windowID);
   if (contentWindow.pendingGetUserMediaRequests)
-    contentWindow.pendingGetUserMediaRequests.delete(aData.callID);
+    forgetRequest(contentWindow, aData.callID);
 }
 
+function forgetRequest(aContentWindow, aCallID) {
+  aContentWindow.pendingGetUserMediaRequests.delete(aCallID);
+  if (aContentWindow.pendingGetUserMediaRequests.size)
+    return;
+
+  aContentWindow.removeEventListener("unload", ContentWebRTC);
+  aContentWindow.pendingGetUserMediaRequests = null;
+}
 
 function updateIndicators() {
   let contentWindowSupportsArray = MediaManagerService.activeMediaCaptureWindows;
   let count = contentWindowSupportsArray.Count();
 
   let state = {
     showGlobalIndicator: count > 0,
     showCameraIndicator: false,
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -23,30 +23,32 @@ this.webrtcUI = {
     let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
                  .getService(Ci.nsIMessageBroadcaster);
     ppmm.addMessageListener("webrtc:UpdatingIndicators", this);
     ppmm.addMessageListener("webrtc:UpdateGlobalIndicators", this);
 
     let mm = Cc["@mozilla.org/globalmessagemanager;1"]
                .getService(Ci.nsIMessageListenerManager);
     mm.addMessageListener("webrtc:Request", this);
+    mm.addMessageListener("webrtc:CancelRequest", this);
     mm.addMessageListener("webrtc:UpdateBrowserIndicators", this);
   },
 
   uninit: function () {
     Services.obs.removeObserver(maybeAddMenuIndicator, "browser-delayed-startup-finished");
 
     let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
                  .getService(Ci.nsIMessageBroadcaster);
     ppmm.removeMessageListener("webrtc:UpdatingIndicators", this);
     ppmm.removeMessageListener("webrtc:UpdateGlobalIndicators", this);
 
     let mm = Cc["@mozilla.org/globalmessagemanager;1"]
                .getService(Ci.nsIMessageListenerManager);
     mm.removeMessageListener("webrtc:Request", this);
+    mm.removeMessageListener("webrtc:CancelRequest", this);
     mm.removeMessageListener("webrtc:UpdateBrowserIndicators", this);
   },
 
   showGlobalIndicator: false,
   showCameraIndicator: false,
   showMicrophoneIndicator: false,
   showScreenSharingIndicator: "", // either "Application", "Screen" or "Window"
 
@@ -120,16 +122,19 @@ this.webrtcUI = {
     popupnotification.setAttribute("buttonlabel", bundle.getString(stringId));
   },
 
   receiveMessage: function(aMessage) {
     switch (aMessage.name) {
       case "webrtc:Request":
         prompt(aMessage.target, aMessage.data);
         break;
+      case "webrtc:CancelRequest":
+        removePrompt(aMessage.target, aMessage.data);
+        break;
       case "webrtc:UpdatingIndicators":
         webrtcUI._streams = [];
         break;
       case "webrtc:UpdateGlobalIndicators":
         updateIndicators(aMessage.data)
         break;
       case "webrtc:UpdateBrowserIndicators":
         webrtcUI._streams.push({browser: aMessage.target, state: aMessage.data});
@@ -432,16 +437,25 @@ function prompt(aBrowser, aRequest) {
   if (requestTypes.length == 1 && requestTypes[0] == "Microphone")
     anchorId = "webRTC-shareMicrophone-notification-icon";
   if (requestTypes.indexOf("Screen") != -1)
     anchorId = "webRTC-shareScreen-notification-icon";
   notification =
     chromeWin.PopupNotifications.show(aBrowser, "webRTC-shareDevices", message,
                                       anchorId, mainAction, secondaryActions,
                                       options);
+  notification.callID = aRequest.callID;
+}
+
+function removePrompt(aBrowser, aCallId) {
+  let chromeWin = aBrowser.ownerDocument.defaultView;
+  let notification =
+    chromeWin.PopupNotifications.getNotification("webRTC-shareDevices", aBrowser);
+  if (notification && notification.callID == aCallId)
+    notification.remove();
 }
 
 function getGlobalIndicator() {
 #ifndef XP_MACOSX
   const INDICATOR_CHROME_URI = "chrome://browser/content/webrtcIndicator.xul";
   const features = "chrome,dialog=yes,titlebar=no,popup=yes";
 
   return Services.ww.openWindow(null, INDICATOR_CHROME_URI, "_blank", features, []);