Bug 1107967 - 'Stop sharing' doesn't work on teared off tabs, r=felipe, a=Sylvestre.
authorFlorian Quèze <florian@queze.net>
Thu, 11 Dec 2014 00:02:39 +0100
changeset 242382 61340b38dced37931ad0b1bad933a6cd9002c9bc
parent 242381 db07de61c0c3cf7c46dd68acff5793d2e052d784
child 242383 27ff5a764eca5321bbaa81267b0033e9a9d31664
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe, Sylvestre
bugs1107967
milestone36.0a2
Bug 1107967 - 'Stop sharing' doesn't work on teared off tabs, r=felipe, a=Sylvestre.
browser/modules/webrtcUI.jsm
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -65,16 +65,23 @@ this.webrtcUI = {
       let browser = aStream.browser;
       let browserWindow = browser.ownerDocument.defaultView;
       let tab = browserWindow.gBrowser &&
                 browserWindow.gBrowser.getTabForBrowser(browser);
       return {uri: state.documentURI, tab: tab, browser: browser, types: types};
     });
   },
 
+  swapBrowserForNotification: function(aOldBrowser, aNewBrowser) {
+    for (let stream of this._streams) {
+      if (stream.browser == aOldBrowser)
+        stream.browser = aNewBrowser;
+    };
+  },
+
   showSharingDoorhanger: function(aActiveStream, aType) {
     let browserWindow = aActiveStream.browser.ownerDocument.defaultView;
     if (aActiveStream.tab) {
       browserWindow.gBrowser.selectedTab = aActiveStream.tab;
     } else {
       aActiveStream.browser.focus();
     }
     browserWindow.focus();
@@ -179,41 +186,43 @@ function prompt(aBrowser, aRequest) {
   let mainLabel;
   if (sharingScreen) {
     mainLabel = stringBundle.getString("getUserMedia.shareSelectedItems.label");
   }
   else {
     let string = stringBundle.getString("getUserMedia.shareSelectedDevices.label");
     mainLabel = PluralForm.get(requestTypes.length, string);
   }
+
+  let notification; // Used by action callbacks.
   let mainAction = {
     label: mainLabel,
     accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"),
     // The real callback will be set during the "showing" event. The
     // empty function here is so that PopupNotifications.show doesn't
     // reject the action.
     callback: function() {}
   };
 
   let secondaryActions = [
     {
       label: stringBundle.getString("getUserMedia.denyRequest.label"),
       accessKey: stringBundle.getString("getUserMedia.denyRequest.accesskey"),
       callback: function () {
-        denyRequest(aBrowser, aRequest);
+        denyRequest(notification.browser, aRequest);
       }
     }
   ];
 
   if (!sharingScreen) { // Bug 1037438: implement 'never' for screen sharing.
     secondaryActions.push({
       label: stringBundle.getString("getUserMedia.never.label"),
       accessKey: stringBundle.getString("getUserMedia.never.accesskey"),
       callback: function () {
-        denyRequest(aBrowser, aRequest);
+        denyRequest(notification.browser, aRequest);
         // Let someone save "Never" for http sites so that they can be stopped from
         // bothering you with doorhangers.
         let perms = Services.perms;
         if (audioDevices.length)
           perms.add(uri, "microphone", perms.DENY_ACTION);
         if (videoDevices.length)
           perms.add(uri, "camera", perms.DENY_ACTION);
       }
@@ -277,20 +286,20 @@ function prompt(aBrowser, aRequest) {
         // and will grant audio access immediately.
         if ((!audioDevices.length || micPerm) && (!videoDevices.length || camPerm)) {
           // All permissions we were about to request are already persistently set.
           let allowedDevices = [];
           if (videoDevices.length && camPerm == perms.ALLOW_ACTION)
             allowedDevices.push(videoDevices[0].deviceIndex);
           if (audioDevices.length && micPerm == perms.ALLOW_ACTION)
             allowedDevices.push(audioDevices[0].deviceIndex);
-          aBrowser.messageManager.sendAsyncMessage("webrtc:Allow",
-                                                   {callID: aRequest.callID,
-                                                    windowID: aRequest.windowID,
-                                                    devices: allowedDevices});
+          let mm = this.browser.messageManager;
+          mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
+                                               windowID: aRequest.windowID,
+                                               devices: allowedDevices});
           this.remove();
           return true;
         }
       }
 
       function listDevices(menupopup, devices) {
         while (menupopup.lastChild)
           menupopup.removeChild(menupopup.lastChild);
@@ -399,36 +408,38 @@ function prompt(aBrowser, aRequest) {
             allowedDevices.push(audioDeviceIndex);
           if (aRemember) {
             perms.add(uri, "microphone",
                       allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION);
           }
         }
 
         if (!allowedDevices.length) {
-          denyRequest(aBrowser, aRequest);
+          denyRequest(notification.browser, aRequest);
           return;
         }
 
-        aBrowser.messageManager.sendAsyncMessage("webrtc:Allow",
-                                                 {callID: aRequest.callID,
-                                                  windowID: aRequest.windowID,
-                                                  devices: allowedDevices});
+        let mm = notification.browser.messageManager
+        mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
+                                             windowID: aRequest.windowID,
+                                             devices: allowedDevices});
       };
       return false;
     }
   };
 
   let anchorId = "webRTC-shareDevices-notification-icon";
   if (requestTypes.length == 1 && requestTypes[0] == "Microphone")
     anchorId = "webRTC-shareMicrophone-notification-icon";
   if (requestTypes.indexOf("Screen") != -1)
     anchorId = "webRTC-shareScreen-notification-icon";
-  chromeWin.PopupNotifications.show(aBrowser, "webRTC-shareDevices", message,
-                                    anchorId, mainAction, secondaryActions, options);
+  notification =
+    chromeWin.PopupNotifications.show(aBrowser, "webRTC-shareDevices", message,
+                                      anchorId, mainAction, secondaryActions,
+                                      options);
 }
 
 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, []);
@@ -696,16 +707,17 @@ function updateBrowserSpecificIndicator(
   } else if (aState.microphone) {
     captureState = "Microphone";
   }
 
   let chromeWin = aBrowser.ownerDocument.defaultView;
   let stringBundle = chromeWin.gNavigatorBundle;
 
   let windowId = aState.windowId;
+  let notification; // Used by action callbacks.
   let mainAction = {
     label: stringBundle.getString("getUserMedia.continueSharing.label"),
     accessKey: stringBundle.getString("getUserMedia.continueSharing.accesskey"),
     callback: function () {},
     dismiss: true
   };
   let secondaryActions = [{
     label: stringBundle.getString("getUserMedia.stopSharing.label"),
@@ -716,73 +728,89 @@ function updateBrowserSpecificIndicator(
       let perms = Services.perms;
       if (aState.camera &&
           perms.testExactPermission(uri, "camera") == perms.ALLOW_ACTION)
         perms.remove(host, "camera");
       if (aState.microphone &&
           perms.testExactPermission(uri, "microphone") == perms.ALLOW_ACTION)
         perms.remove(host, "microphone");
 
-      aBrowser.messageManager.sendAsyncMessage("webrtc:StopSharing", windowId);
+      let mm = notification.browser.messageManager;
+      mm.sendAsyncMessage("webrtc:StopSharing", windowId);
     }
   }];
   let options = {
     hideNotNow: true,
     dismissed: true,
-    eventCallback: function(aTopic) {
+    eventCallback: function(aTopic, aNewBrowser) {
       if (aTopic == "shown") {
         let PopupNotifications = this.browser.ownerDocument.defaultView.PopupNotifications;
         let popupId = captureState == "Microphone" ? "Microphone" : "Devices";
         PopupNotifications.panel.firstChild.setAttribute("popupid", "webRTC-sharing" + popupId);
       }
-      return aTopic == "swapping";
+
+      if (aTopic == "swapping") {
+        webrtcUI.swapBrowserForNotification(this.browser, aNewBrowser);
+        return true;
+      }
+
+      return false;
     }
   };
   if (captureState) {
     let anchorId = captureState == "Microphone" ? "webRTC-sharingMicrophone-notification-icon"
                                                 : "webRTC-sharingDevices-notification-icon";
     let message = stringBundle.getString("getUserMedia.sharing" + captureState + ".message2");
-    chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message,
-                                      anchorId, mainAction, secondaryActions, options);
+    notification =
+      chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message,
+                                        anchorId, mainAction, secondaryActions, options);
   }
   else {
     removeBrowserNotification(aBrowser,"webRTC-sharingDevices");
   }
 
   // Now handle the screen sharing indicator.
   if (!aState.screen) {
     removeBrowserNotification(aBrowser,"webRTC-sharingScreen");
     return;
   }
 
+  let screenSharingNotif; // Used by action callbacks.
   options = {
     hideNotNow: true,
     dismissed: true,
-    eventCallback: function(aTopic) {
+    eventCallback: function(aTopic, aNewBrowser) {
       if (aTopic == "shown") {
         let PopupNotifications = this.browser.ownerDocument.defaultView.PopupNotifications;
         PopupNotifications.panel.firstChild.setAttribute("popupid", "webRTC-sharingScreen");
       }
-      return aTopic == "swapping";
+
+      if (aTopic == "swapping") {
+        webrtcUI.swapBrowserForNotification(this.browser, aNewBrowser);
+        return true;
+      }
+
+      return false;
     }
   };
   secondaryActions = [{
     label: stringBundle.getString("getUserMedia.stopSharing.label"),
     accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
     callback: function () {
-      aBrowser.messageManager.sendAsyncMessage("webrtc:StopSharing",
-                                               "screen:" + windowId);
+      let mm = screenSharingNotif.browser.messageManager;
+      mm.sendAsyncMessage("webrtc:StopSharing", "screen:" + windowId);
     }
   }];
   // If we are sharing both a window and the screen, we show 'Screen'.
   let stringId = "getUserMedia.sharing" + aState.screen;
-  chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingScreen",
-                                    stringBundle.getString(stringId + ".message"),
-                                    "webRTC-sharingScreen-notification-icon",
-                                    mainAction, secondaryActions, options);
+  screenSharingNotif =
+    chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingScreen",
+                                      stringBundle.getString(stringId + ".message"),
+                                      "webRTC-sharingScreen-notification-icon",
+                                      mainAction, secondaryActions, options);
 }
 
 function removeBrowserNotification(aBrowser, aNotificationId) {
   let win = aBrowser.ownerDocument.defaultView;
   let notification =
     win.PopupNotifications.getNotification(aNotificationId, aBrowser);
   if (notification)
     win.PopupNotifications.remove(notification);