Bug 1139907: show WebRTC screen sharing notification icon in Hello conversation window and globally when tab sharing is active. r=jesup,florian, a=lsblakk
authorMike de Boer <mdeboer@mozilla.com>
Wed, 11 Mar 2015 16:34:31 +0100
changeset 248121 8acc69cac05d31cfa5d9ef9aaaaece3be8fce29f
parent 248120 6c5849a66b1ac07ce819846a578b44d1e8ba8b87
child 248122 249da78cf780e9ca20aafea915f526d8f0d4f4b0
push id7762
push usermdeboer@mozilla.com
push dateMon, 16 Mar 2015 15:07:09 +0000
treeherdermozilla-aurora@9b59f3a2743d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, florian, lsblakk
bugs1139907
milestone38.0a2
Bug 1139907: show WebRTC screen sharing notification icon in Hello conversation window and globally when tab sharing is active. r=jesup,florian, a=lsblakk
browser/base/content/webrtcIndicator.js
browser/modules/ContentWebRTC.jsm
browser/modules/webrtcUI.jsm
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/nsIMediaManager.idl
--- a/browser/base/content/webrtcIndicator.js
+++ b/browser/base/content/webrtcIndicator.js
@@ -52,18 +52,21 @@ function updateIndicatorState() {
   }
   else {
     audioVideoButton.removeAttribute("tooltiptext");
   }
 
   // Screen sharing button tooltip.
   let screenShareButton = document.getElementById("screenShareButton");
   if (webrtcUI.showScreenSharingIndicator) {
-    let stringId = "webrtcIndicator.sharing" +
-                   webrtcUI.showScreenSharingIndicator + ".tooltip";
+    // This can be removed once strings are added for type 'Browser' in bug 1142066.
+    let typeForL10n = webrtcUI.showScreenSharingIndicator;
+    if (typeForL10n == "Browser")
+      typeForL10n = "Window";
+    let stringId = "webrtcIndicator.sharing" + typeForL10n + ".tooltip";
     screenShareButton.setAttribute("tooltiptext",
                                     gStringBundle.GetStringFromName(stringId));
   }
   else {
     screenShareButton.removeAttribute("tooltiptext");
   }
 
   // Resize and ensure the window position is correct
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -184,19 +184,19 @@ function updateIndicators() {
   // have the same top level window several times. We use a Set to avoid
   // sending duplicate notifications.
   let contentWindows = new Set();
   for (let i = 0; i < count; ++i) {
     contentWindows.add(contentWindowSupportsArray.GetElementAt(i).top);
   }
 
   for (let contentWindow of contentWindows) {
-    let camera = {}, microphone = {}, screen = {}, window = {}, app = {};
-    MediaManagerService.mediaCaptureWindowState(contentWindow, camera,
-                                                microphone, screen, window, app);
+    let camera = {}, microphone = {}, screen = {}, window = {}, app = {}, browser = {};
+    MediaManagerService.mediaCaptureWindowState(contentWindow, camera, microphone,
+                                                screen, window, app, browser);
     let tabState = {camera: camera.value, microphone: microphone.value};
     if (camera.value)
       state.showCameraIndicator = true;
     if (microphone.value)
       state.showMicrophoneIndicator = true;
     if (screen.value) {
       state.showScreenSharingIndicator = "Screen";
       tabState.screen = "Screen";
@@ -206,16 +206,21 @@ function updateIndicators() {
         state.showScreenSharingIndicator = "Window";
       tabState.screen = "Window";
     }
     else if (app.value) {
       if (!state.showScreenSharingIndicator)
         state.showScreenSharingIndicator = "Application";
       tabState.screen = "Application";
     }
+    else if (browser.value) {
+      if (!state.showScreenSharingIndicator)
+        state.showScreenSharingIndicator = "Browser";
+      tabState.screen = "Browser";
+    }
 
     tabState.windowId = getInnerWindowIDForWindow(contentWindow);
     tabState.documentURI = contentWindow.document.documentURI;
     let mm = getMessageManagerForWindow(contentWindow);
     mm.sendAsyncMessage("webrtc:UpdateBrowserIndicators", tabState);
   }
 
   cpmm.sendAsyncMessage("webrtc:UpdateGlobalIndicators", state);
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -45,17 +45,17 @@ this.webrtcUI = {
     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"
+  showScreenSharingIndicator: "", // either "Application", "Screen", "Window" or "Browser"
 
   _streams: [],
   // The boolean parameters indicate which streams should be included in the result.
   getActiveStreams: function(aCamera, aMicrophone, aScreen) {
     return webrtcUI._streams.filter(aStream => {
       let state = aStream.state;
       return aCamera && state.camera ||
              aMicrophone && state.microphone ||
@@ -470,43 +470,46 @@ function getGlobalIndicator() {
                   .hiddenDOMWindow.document,
     _statusBar: Cc["@mozilla.org/widget/macsystemstatusbar;1"]
                   .getService(Ci.nsISystemStatusBar),
 
     _command: function(aEvent) {
       let type = this.getAttribute("type");
       if (type == "Camera" || type == "Microphone")
         type = "Devices";
-      else if (type == "Window" || type == "Application")
+      else if (type == "Window" || type == "Application" || type == "Browser")
         type = "Screen";
       webrtcUI.showSharingDoorhanger(aEvent.target.stream, type);
     },
 
     _popupShowing: function(aEvent) {
       let type = this.getAttribute("type");
+      // This can be removed once strings are added for type 'Browser' in bug 1142066.
+      let typeForL10n = type;
       let activeStreams;
       if (type == "Camera") {
         activeStreams = webrtcUI.getActiveStreams(true, false, false);
       }
       else if (type == "Microphone") {
         activeStreams = webrtcUI.getActiveStreams(false, true, false);
       }
       else if (type == "Screen") {
         activeStreams = webrtcUI.getActiveStreams(false, false, true);
         type = webrtcUI.showScreenSharingIndicator;
+        typeForL10n = type == "Browser" ? "Window" : type;
       }
 
       let bundle =
         Services.strings.createBundle("chrome://browser/locale/webrtcIndicator.properties");
 
       if (activeStreams.length == 1) {
         let stream = activeStreams[0];
 
         let menuitem = this.ownerDocument.createElement("menuitem");
-        let labelId = "webrtcIndicator.sharing" + type + "With.menuitem";
+        let labelId = "webrtcIndicator.sharing" + typeForL10n + "With.menuitem";
         let label = stream.browser.contentTitle || stream.uri;
         menuitem.setAttribute("label", bundle.formatStringFromName(labelId, [label], 1));
         menuitem.setAttribute("disabled", "true");
         this.appendChild(menuitem);
 
         menuitem = this.ownerDocument.createElement("menuitem");
         menuitem.setAttribute("label",
                               bundle.GetStringFromName("webrtcIndicator.controlSharing.menuitem"));
@@ -515,17 +518,17 @@ function getGlobalIndicator() {
         menuitem.addEventListener("command", indicator._command);
 
         this.appendChild(menuitem);
         return true;
       }
 
       // We show a different menu when there are several active streams.
       let menuitem = this.ownerDocument.createElement("menuitem");
-      let labelId = "webrtcIndicator.sharing" + type + "WithNTabs.menuitem";
+      let labelId = "webrtcIndicator.sharing" + typeForL10n + "WithNTabs.menuitem";
       let count = activeStreams.length;
       let label = PluralForm.get(count, bundle.GetStringFromName(labelId)).replace("#1", count);
       menuitem.setAttribute("label", label);
       menuitem.setAttribute("disabled", "true");
       this.appendChild(menuitem);
 
       for (let stream of activeStreams) {
         let item = this.ownerDocument.createElement("menuitem");
@@ -785,18 +788,19 @@ function updateBrowserSpecificIndicator(
 
   // Now handle the screen sharing indicator.
   if (!aState.screen) {
     removeBrowserNotification(aBrowser,"webRTC-sharingScreen");
     return;
   }
 
   let screenSharingNotif; // Used by action callbacks.
+  let isBrowserSharing = aState.screen == "Browser";
   options = {
-    hideNotNow: true,
+    hideNotNow: !isBrowserSharing,
     dismissed: true,
     eventCallback: function(aTopic, aNewBrowser) {
       if (aTopic == "shown") {
         let PopupNotifications = this.browser.ownerDocument.defaultView.PopupNotifications;
         PopupNotifications.panel.firstChild.setAttribute("popupid", "webRTC-sharingScreen");
       }
 
       if (aTopic == "swapping") {
@@ -810,18 +814,23 @@ function updateBrowserSpecificIndicator(
   secondaryActions = [{
     label: stringBundle.getString("getUserMedia.stopSharing.label"),
     accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
     callback: function () {
       let mm = screenSharingNotif.browser.messageManager;
       mm.sendAsyncMessage("webrtc:StopSharing", "screen:" + windowId);
     }
   }];
+
+  // Ending browser-sharing from the gUM doorhanger is not supported at the moment.
+  // See bug 1142091.
+  if (isBrowserSharing)
+    mainAction = secondaryActions = null;
   // If we are sharing both a window and the screen, we show 'Screen'.
-  let stringId = "getUserMedia.sharing" + aState.screen;
+  let stringId = "getUserMedia.sharing" + (isBrowserSharing ? "Window" : aState.screen);
   screenSharingNotif =
     chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingScreen",
                                       stringBundle.getString(stringId + ".message"),
                                       "webRTC-sharingScreen-notification-icon",
                                       mainAction, secondaryActions, options);
 }
 
 function removeBrowserNotification(aBrowser, aNotificationId) {
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2162,16 +2162,17 @@ MediaManager::GetActiveMediaCaptureWindo
 
 // XXX flags might be better...
 struct CaptureWindowStateData {
   bool *mVideo;
   bool *mAudio;
   bool *mScreenShare;
   bool *mWindowShare;
   bool *mAppShare;
+  bool *mBrowserShare;
 };
 
 static void
 CaptureWindowStateCallback(MediaManager *aThis,
                            uint64_t aWindowID,
                            StreamListeners *aListeners,
                            void *aData)
 {
@@ -2192,49 +2193,55 @@ CaptureWindowStateCallback(MediaManager 
         *data->mScreenShare = true;
       }
       if (listener->CapturingWindow()) {
         *data->mWindowShare = true;
       }
       if (listener->CapturingApplication()) {
         *data->mAppShare = true;
       }
+      if (listener->CapturingBrowser()) {
+        *data->mBrowserShare = true;
+      }
     }
   }
 }
 
 
 NS_IMETHODIMP
 MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow, bool* aVideo,
                                       bool* aAudio, bool *aScreenShare,
-                                      bool* aWindowShare, bool *aAppShare)
+                                      bool* aWindowShare, bool *aAppShare,
+                                      bool *aBrowserShare)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   struct CaptureWindowStateData data;
   data.mVideo = aVideo;
   data.mAudio = aAudio;
   data.mScreenShare = aScreenShare;
   data.mWindowShare = aWindowShare;
   data.mAppShare = aAppShare;
+  data.mBrowserShare = aBrowserShare;
 
   *aVideo = false;
   *aAudio = false;
   *aScreenShare = false;
   *aWindowShare = false;
   *aAppShare = false;
+  *aBrowserShare = false;
 
   nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
   if (piWin) {
     IterateWindowListeners(piWin, CaptureWindowStateCallback, &data);
   }
 #ifdef DEBUG
-  LOG(("%s: window %lld capturing %s %s %s %s %s", __FUNCTION__, piWin ? piWin->WindowID() : -1,
+  LOG(("%s: window %lld capturing %s %s %s %s %s %s", __FUNCTION__, piWin ? piWin->WindowID() : -1,
        *aVideo ? "video" : "", *aAudio ? "audio" : "",
        *aScreenShare ? "screenshare" : "",  *aWindowShare ? "windowshare" : "",
-       *aAppShare ? "appshare" : ""));
+       *aAppShare ? "appshare" : "", *aBrowserShare ? "browsershare" : ""));
 #endif
   return NS_OK;
 }
 
 static void
 StopScreensharingCallback(MediaManager *aThis,
                           uint64_t aWindowID,
                           StreamListeners *aListeners,
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -140,16 +140,22 @@ public:
            mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Window;
   }
   bool CapturingApplication()
   {
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
     return mVideoSource && !mStopped && !mVideoSource->IsAvailable() &&
            mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Application;
   }
+  bool CapturingBrowser()
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+    return mVideoSource && !mStopped && mVideoSource->IsAvailable() &&
+           mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Browser;
+  }
 
   void SetStopped()
   {
     mStopped = true;
   }
 
   // implement in .cpp to avoid circular dependency with MediaOperationTask
   // Can be invoked from EITHER MainThread or MSG thread
--- a/dom/media/nsIMediaManager.idl
+++ b/dom/media/nsIMediaManager.idl
@@ -7,19 +7,19 @@
 interface nsISupportsArray;
 interface nsIDOMWindow;
 
 %{C++
 #define NS_MEDIAMANAGERSERVICE_CID {0xabc622ea, 0x9655, 0x4123, {0x80, 0xd9, 0x22, 0x62, 0x1b, 0xdd, 0x54, 0x65}}
 #define MEDIAMANAGERSERVICE_CONTRACTID "@mozilla.org/mediaManagerService;1"
 %}
 
-[scriptable, builtinclass, uuid(2ab0e6f7-9a5b-4b9a-901d-145531f47a6b)]
+[scriptable, builtinclass, uuid(9b10661f-77b3-47f7-a8de-ee58daaff5d2)]
 interface nsIMediaManagerService : nsISupports
 {
   /* return a array of inner windows that have active captures */
   readonly attribute nsISupportsArray activeMediaCaptureWindows;
 
   /* Get the capture state for the given window and all descendant windows (iframes, etc) */
   void mediaCaptureWindowState(in nsIDOMWindow aWindow, out boolean aVideo, out boolean aAudio,
                                [optional] out boolean aScreenShare, [optional] out boolean aWindowShare,
-                               [optional] out boolean aAppShare);
+                               [optional] out boolean aAppShare, [optional] out boolean aBrowserShare);
 };