Bug 1139907: show WebRTC screen sharing notification icon in Hello conversation window and globally when tab sharing is active. r=jesup,florian
authorMike de Boer <mdeboer@mozilla.com>
Wed, 11 Mar 2015 16:34:31 +0100
changeset 233186 9cfd185f1ff890bd4bee7d5a7d4b9a65628c4620
parent 233185 d3cf2d70afa5de67ab5ed3891200061a4eb2ad48
child 233187 e026b87b725e3919bb1d47d81af6ebdee14a03f4
push id28404
push usercbook@mozilla.com
push dateThu, 12 Mar 2015 09:18:19 +0000
treeherdermozilla-central@58c9d079f318 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, florian
bugs1139907
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1139907: show WebRTC screen sharing notification icon in Hello conversation window and globally when tab sharing is active. r=jesup,florian
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
@@ -2171,16 +2171,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)
 {
@@ -2201,49 +2202,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);
 };