Bug 1208417 - Part 2 - Add DisplayDeviceProvider to Presentation API, r=schien, r=smaug
authorKuoE0 <kuoe0.tw@gmail.com>
Thu, 28 Apr 2016 15:05:25 +0800
changeset 295177 4f95de9b438f19200f3399814348ea6dda563bc1
parent 295176 eaa9bd3a5d1b59b142dfaadab6ee3b43ffc11c7c
child 295178 c2da65057928abc7fb07c061c0581b743a7baec1
push id75837
push usergachen@mozilla.com
push dateThu, 28 Apr 2016 07:07:10 +0000
treeherdermozilla-inbound@c2da65057928 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersschien, smaug
bugs1208417
milestone49.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 1208417 - Part 2 - Add DisplayDeviceProvider to Presentation API, r=schien, r=smaug
b2g/chrome/content/shell.js
b2g/components/MultiscreenHandler.jsm
b2g/components/moz.build
dom/presentation/interfaces/nsIPresentationDevice.idl
dom/presentation/provider/DisplayDeviceProvider.cpp
dom/presentation/provider/DisplayDeviceProvider.h
dom/presentation/provider/MulticastDNSDeviceProvider.cpp
dom/presentation/provider/PresentationDeviceProviderModule.cpp
dom/presentation/provider/moz.build
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -16,17 +16,16 @@ Cu.import("resource://gre/modules/AppsUt
 Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
 Cu.import('resource://gre/modules/Keyboard.jsm');
 Cu.import('resource://gre/modules/ErrorPage.jsm');
 Cu.import('resource://gre/modules/AlertsHelper.jsm');
 Cu.import('resource://gre/modules/RequestSyncService.jsm');
 Cu.import('resource://gre/modules/SystemUpdateService.jsm');
 
 if (isGonk) {
-  Cu.import('resource://gre/modules/MultiscreenHandler.jsm');
   Cu.import('resource://gre/modules/NetworkStatsService.jsm');
   Cu.import('resource://gre/modules/ResourceStatsService.jsm');
 }
 
 Cu.import('resource://gre/modules/KillSwitchMain.jsm');
 
 // Identity
 Cu.import('resource://gre/modules/SignInToWebsite.jsm');
deleted file mode 100644
--- a/b2g/components/MultiscreenHandler.jsm
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["MultiscreenHandler"];
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-function debug(aStr) {
-  // dump("MultiscreenHandler: " + aStr + "\n");
-}
-
-var window = Services.wm.getMostRecentWindow("navigator:browser");
-
-// Multi-screen support on b2g. The following implementation will open a new
-// top-level window once we receive a display connected event.
-var MultiscreenHandler = {
-
-  topLevelWindows: new Map(),
-
-  init: function init() {
-    Services.obs.addObserver(this, "display-changed", false);
-    Services.obs.addObserver(this, "xpcom-shutdown", false);
-  },
-
-  uninit: function uninit() {
-    Services.obs.removeObserver(this, "display-changed");
-    Services.obs.removeObserver(this, "xpcom-shutdown");
-  },
-
-  observe: function observe(aSubject, aTopic, aData) {
-    switch (aTopic) {
-      case "display-changed":
-        this.handleDisplayChangeEvent(aSubject);
-        break
-      case "xpcom-shutdown":
-        this.uninit();
-        break
-    }
-  },
-
-  openTopLevelWindow: function openTopLevelWindow(aDisplay) {
-    if (this.topLevelWindows.get(aDisplay.id)) {
-      debug("Top level window for display id: " + aDisplay.id + " has been opened.");
-      return;
-    }
-
-    let flags = Services.prefs.getCharPref("toolkit.defaultChromeFeatures") +
-                ",mozDisplayId=" + aDisplay.id;
-    let remoteShellURL = Services.prefs.getCharPref("b2g.multiscreen.chrome_remote_url") +
-                         "#" + aDisplay.id;
-    let win = Services.ww.openWindow(null, remoteShellURL, "myTopWindow" + aDisplay.id, flags, null);
-
-    this.topLevelWindows.set(aDisplay.id, win);
-  },
-
-  closeTopLevelWindow: function closeTopLevelWindow(aDisplay) {
-    let win = this.topLevelWindows.get(aDisplay.id);
-
-    if (win) {
-      win.close();
-      this.topLevelWindows.delete(aDisplay.id);
-    }
-  },
-
-  handleDisplayChangeEvent: function handleDisplayChangeEvent(aSubject) {
-
-    let display = aSubject.QueryInterface(Ci.nsIDisplayInfo);
-    let name = "multiscreen.enabled";
-    let req = window.navigator.mozSettings.createLock().get(name);
-
-    req.addEventListener("success", () => {
-      let isMultiscreenEnabled = req.result[name];
-      if (display.connected) {
-        if (isMultiscreenEnabled) {
-          this.openTopLevelWindow(display);
-        }
-      } else {
-        this.closeTopLevelWindow(display);
-      }
-    });
-  },
-
-};
-
-MultiscreenHandler.init();
-this.MultiscreenHandler = MultiscreenHandler;
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -63,17 +63,16 @@ EXTRA_JS_MODULES += [
     'DebuggerActors.js',
     'ErrorPage.jsm',
     'Frames.jsm',
     'FxAccountsMgmtService.jsm',
     'KillSwitchMain.jsm',
     'LogCapture.jsm',
     'LogParser.jsm',
     'LogShake.jsm',
-    'MultiscreenHandler.jsm',
     'OrientationChangeHandler.jsm',
     'PersistentDataBlock.jsm',
     'SafeMode.jsm',
     'Screenshot.jsm',
     'SignInToWebsite.jsm',
     'SystemAppProxy.jsm',
     'TelURIParser.jsm',
     'WebappsUpdater.jsm',
--- a/dom/presentation/interfaces/nsIPresentationDevice.idl
+++ b/dom/presentation/interfaces/nsIPresentationDevice.idl
@@ -30,8 +30,10 @@ interface nsIPresentationDevice : nsISup
    * @throws  NS_ERROR_FAILURE if the establishment fails
    */
   nsIPresentationControlChannel establishControlChannel(in DOMString url,
                                                         in DOMString presentationId);
 
   // Do something when presentation session is disconnected.
   void disconnect();
 };
+
+
new file mode 100644
--- /dev/null
+++ b/dom/presentation/provider/DisplayDeviceProvider.cpp
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DisplayDeviceProvider.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+#include "mozilla/unused.h"
+#include "nsIObserverService.h"
+#include "nsIServiceManager.h"
+#include "nsIWindowWatcher.h"
+#include "nsNetUtil.h"
+#include "nsPIDOMWindow.h"
+#include "nsSimpleURI.h"
+#include "nsThreadUtils.h"
+
+static mozilla::LazyLogModule gDisplayDeviceProviderLog("DisplayDeviceProvider");
+
+#define LOG(format) MOZ_LOG(gDisplayDeviceProviderLog, mozilla::LogLevel::Debug, format)
+
+#define DISPLAY_CHANGED_NOTIFICATION "display-changed"
+#define DEFAULT_CHROME_FEATURES_PREF "toolkit.defaultChromeFeatures"
+#define CHROME_REMOTE_URL_PREF       "b2g.multiscreen.chrome_remote_url"
+
+namespace mozilla {
+namespace dom {
+namespace presentation {
+
+NS_IMPL_ISUPPORTS(DisplayDeviceProvider::HDMIDisplayDevice,
+                  nsIPresentationDevice,
+                  nsIPresentationLocalDevice)
+
+// nsIPresentationDevice
+NS_IMETHODIMP
+DisplayDeviceProvider::HDMIDisplayDevice::GetId(nsACString& aId)
+{
+  aId = mWindowId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::HDMIDisplayDevice::GetName(nsACString& aName)
+{
+  aName = mName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::HDMIDisplayDevice::GetType(nsACString& aType)
+{
+  aType = mType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::HDMIDisplayDevice::GetWindowId(nsACString& aWindowId)
+{
+  aWindowId = mWindowId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::HDMIDisplayDevice
+                     ::EstablishControlChannel(const nsAString& aUrl,
+                                               const nsAString& aPresentationId,
+                                               nsIPresentationControlChannel** aControlChannel)
+{
+  nsresult rv = OpenTopLevelWindow();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  RefPtr<DisplayDeviceProvider> provider = mProvider.get();
+  if (NS_WARN_IF(!provider)) {
+    return NS_ERROR_FAILURE;
+  }
+  return provider->RequestSession(this, aUrl, aPresentationId, aControlChannel);
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::HDMIDisplayDevice::Disconnect()
+{
+  nsresult rv = CloseTopLevelWindow();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+  }
+  return NS_OK;;
+}
+
+nsresult
+DisplayDeviceProvider::HDMIDisplayDevice::OpenTopLevelWindow()
+{
+  MOZ_ASSERT(!mWindow);
+
+  nsresult rv;
+  nsAutoCString flags(Preferences::GetCString(DEFAULT_CHROME_FEATURES_PREF));
+  if (flags.IsEmpty()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  flags.AppendLiteral(",mozDisplayId=");
+  flags.AppendInt(mScreenId);
+
+  nsAutoCString remoteShellURLString(Preferences::GetCString(CHROME_REMOTE_URL_PREF));
+  remoteShellURLString.AppendLiteral("#");
+  remoteShellURLString.Append(mWindowId);
+
+  // URI validation
+  nsCOMPtr<nsIURI> remoteShellURL;
+  rv = NS_NewURI(getter_AddRefs(remoteShellURL), remoteShellURLString);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = remoteShellURL->GetSpec(remoteShellURLString);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
+  MOZ_ASSERT(ww);
+
+  rv = ww->OpenWindow(nullptr,
+                      remoteShellURLString.get(),
+                      "_blank",
+                      flags.get(),
+                      nullptr,
+                      getter_AddRefs(mWindow));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::HDMIDisplayDevice::CloseTopLevelWindow()
+{
+  MOZ_ASSERT(mWindow);
+
+  nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(mWindow);
+  nsresult rv = piWindow->Close();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(DisplayDeviceProvider,
+                  nsIObserver,
+                  nsIPresentationDeviceProvider)
+
+DisplayDeviceProvider::~DisplayDeviceProvider()
+{
+  Uninit();
+}
+
+nsresult
+DisplayDeviceProvider::Init()
+{
+  // Provider must be initialized only once.
+  if (mInitialized) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  MOZ_ASSERT(obs);
+
+  obs->AddObserver(this, DISPLAY_CHANGED_NOTIFICATION, false);
+
+  mDevice = new HDMIDisplayDevice(this);
+
+  mInitialized = true;
+  return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::Uninit()
+{
+  // Provider must be deleted only once.
+  if (!mInitialized) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, DISPLAY_CHANGED_NOTIFICATION);
+  }
+
+  // Remove device from device manager when the provider is uninit
+  RemoveExternalScreen();
+
+  mInitialized = false;
+  return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::AddExternalScreen()
+{
+  MOZ_ASSERT(mDeviceListener);
+
+  nsresult rv;
+  nsCOMPtr<nsIPresentationDeviceListener> listener;
+  rv = GetListener(getter_AddRefs(listener));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = listener->AddDevice(mDevice);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::RemoveExternalScreen()
+{
+  MOZ_ASSERT(mDeviceListener);
+
+  nsresult rv;
+  nsCOMPtr<nsIPresentationDeviceListener> listener;
+  rv = GetListener(getter_AddRefs(listener));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = listener->RemoveDevice(mDevice);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mDevice->Disconnect();
+  return NS_OK;
+}
+
+// nsIPresentationDeviceProvider
+NS_IMETHODIMP
+DisplayDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
+{
+  if (NS_WARN_IF(!aListener)) {
+    return NS_ERROR_INVALID_POINTER;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIPresentationDeviceListener> listener =
+    do_QueryReferent(mDeviceListener, &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+  }
+
+  listener.forget(aListener);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::SetListener(nsIPresentationDeviceListener* aListener)
+{
+  mDeviceListener = do_GetWeakReference(aListener);
+  nsresult rv = mDeviceListener ? Init() : Uninit();
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::ForceDiscovery()
+{
+  return NS_OK;
+}
+
+// nsIObserver
+NS_IMETHODIMP
+DisplayDeviceProvider::Observe(nsISupports* aSubject,
+                               const char* aTopic,
+                               const char16_t* aData)
+{
+  if (!strcmp(aTopic, DISPLAY_CHANGED_NOTIFICATION)) {
+    nsCOMPtr<nsIDisplayInfo> displayInfo = do_QueryInterface(aSubject);
+    MOZ_ASSERT(displayInfo);
+
+    int32_t type;
+    bool isConnected;
+    displayInfo->GetConnected(&isConnected);
+    // XXX The ID is as same as the type of display.
+    // See Bug 1138287 and nsScreenManagerGonk::AddScreen() for more detail.
+    displayInfo->GetId(&type);
+
+    if (type == DisplayType::DISPLAY_EXTERNAL) {
+      nsresult rv = isConnected ? AddExternalScreen() : RemoveExternalScreen();
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::RequestSession(HDMIDisplayDevice* aDevice,
+                                    const nsAString& aUrl,
+                                    const nsAString& aPresentationId,
+                                    nsIPresentationControlChannel** aControlChannel)
+{
+  // Implement in part 3
+  return NS_OK;
+}
+
+} // namespace presentation
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/presentation/provider/DisplayDeviceProvider.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_presentation_provider_DisplayDeviceProvider_h
+#define mozilla_dom_presentation_provider_DisplayDeviceProvider_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/WeakPtr.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMWindow.h"
+#include "nsIDisplayInfo.h"
+#include "nsIObserver.h"
+#include "nsIPresentationDeviceProvider.h"
+#include "nsIPresentationLocalDevice.h"
+#include "nsIWindowWatcher.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+namespace dom {
+namespace presentation {
+
+// Consistent definition with the definition in
+// widget/gonk/libdisplay/GonkDisplay.h.
+enum DisplayType {
+    DISPLAY_PRIMARY,
+    DISPLAY_EXTERNAL,
+    DISPLAY_VIRTUAL,
+    NUM_DISPLAY_TYPES
+};
+
+class DisplayDeviceProvider final : public nsIObserver
+                                  , public nsIPresentationDeviceProvider
+                                  , public SupportsWeakPtr<DisplayDeviceProvider>
+{
+private:
+  class HDMIDisplayDevice final : public nsIPresentationLocalDevice
+  {
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIPRESENTATIONDEVICE
+    NS_DECL_NSIPRESENTATIONLOCALDEVICE
+
+    // mScreenId is as same as the definition of display type.
+    explicit HDMIDisplayDevice(DisplayDeviceProvider* aProvider)
+      : mScreenId(DisplayType::DISPLAY_EXTERNAL)
+      , mName("HDMI")
+      , mType("external")
+      , mWindowId("hdmi")
+      , mProvider(aProvider)
+    {}
+
+    nsresult OpenTopLevelWindow();
+    nsresult CloseTopLevelWindow();
+
+    const nsCString& Id() const { return mWindowId; }
+
+  private:
+    virtual ~HDMIDisplayDevice() = default;
+
+    // Due to the limitation of nsWinodw, mScreenId must be an integer.
+    // And mScreenId is also align to the display type defined in
+    // widget/gonk/libdisplay/GonkDisplay.h.
+    // HDMI display is DisplayType::DISPLAY_EXTERNAL.
+    uint32_t mScreenId;
+    nsCString mName;
+    nsCString mType;
+    nsCString mWindowId;
+
+    nsCOMPtr<mozIDOMWindowProxy> mWindow;
+    // weak pointer
+    // Provider hold a strong pointer to the device. Use weak pointer to prevent
+    // the reference cycle.
+    WeakPtr<DisplayDeviceProvider> mProvider;
+  };
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
+  // For using WeakPtr when MOZ_REFCOUNTED_LEAK_CHECKING defined
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(DisplayDeviceProvider)
+
+  nsresult RequestSession(HDMIDisplayDevice* aDevice,
+                          const nsAString& aUrl,
+                          const nsAString& aPresentationId,
+                          nsIPresentationControlChannel** aControlChannel);
+private:
+  virtual ~DisplayDeviceProvider();
+
+  nsresult Init();
+  nsresult Uninit();
+
+  nsresult AddExternalScreen();
+  nsresult RemoveExternalScreen();
+
+  // Now support HDMI display only and there should be only one HDMI display.
+  nsCOMPtr<nsIPresentationLocalDevice> mDevice = nullptr;
+  // weak pointer
+  // PresentationDeviceManager (mDeviceListener) hold strong pointer to
+  // DisplayDeviceProvider. Use nsWeakPtr to avoid reference cycle.
+  nsWeakPtr mDeviceListener = nullptr;
+  bool mInitialized = false;
+};
+
+} // mozilla
+} // dom
+} // presentation
+
+#endif // mozilla_dom_presentation_provider_DisplayDeviceProvider_h
+
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
+++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
@@ -1050,14 +1050,15 @@ MulticastDNSDeviceProvider::Device::Esta
   }
 
   return mProvider->RequestSession(this, aUrl, aPresentationId, aRetVal);
 }
 
 NS_IMETHODIMP
 MulticastDNSDeviceProvider::Device::Disconnect()
 {
+  // No need to do anything when disconnect.
   return NS_OK;
 }
 
 } // namespace presentation
 } // namespace dom
 } // namespace mozilla
--- a/dom/presentation/provider/PresentationDeviceProviderModule.cpp
+++ b/dom/presentation/provider/PresentationDeviceProviderModule.cpp
@@ -1,41 +1,56 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "DisplayDeviceProvider.h"
 #include "MulticastDNSDeviceProvider.h"
 #include "mozilla/ModuleUtils.h"
 
 #define MULTICAST_DNS_PROVIDER_CID \
   {0x814f947a, 0x52f7, 0x41c9, \
     { 0x94, 0xa1, 0x36, 0x84, 0x79, 0x72, 0x84, 0xac }}
+#define DISPLAY_DEVICE_PROVIDER_CID \
+  { 0x515d9879, 0xfe0b, 0x4d9f, \
+    { 0x89, 0x49, 0x7f, 0xa7, 0x65, 0x6c, 0x01, 0x0e } }
 
+
+#define DISPLAY_DEVICE_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/displaydevice-provider;1"
 #define MULTICAST_DNS_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/multicastdns-provider;1"
 
 using mozilla::dom::presentation::MulticastDNSDeviceProvider;
+using mozilla::dom::presentation::DisplayDeviceProvider;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(MulticastDNSDeviceProvider)
 NS_DEFINE_NAMED_CID(MULTICAST_DNS_PROVIDER_CID);
 
+NS_GENERIC_FACTORY_CONSTRUCTOR(DisplayDeviceProvider)
+NS_DEFINE_NAMED_CID(DISPLAY_DEVICE_PROVIDER_CID);
+
 static const mozilla::Module::CIDEntry kPresentationDeviceProviderCIDs[] = {
   { &kMULTICAST_DNS_PROVIDER_CID, false, nullptr, MulticastDNSDeviceProviderConstructor },
+  { &kDISPLAY_DEVICE_PROVIDER_CID, false, nullptr, DisplayDeviceProviderConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kPresentationDeviceProviderContracts[] = {
   { MULTICAST_DNS_PROVIDER_CONTRACT_ID, &kMULTICAST_DNS_PROVIDER_CID },
+  { DISPLAY_DEVICE_PROVIDER_CONTRACT_ID, &kDISPLAY_DEVICE_PROVIDER_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kPresentationDeviceProviderCategories[] = {
 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_ANDROID) || (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16)
   { PRESENTATION_DEVICE_PROVIDER_CATEGORY, "MulticastDNSDeviceProvider", MULTICAST_DNS_PROVIDER_CONTRACT_ID },
 #endif
+#if defined(MOZ_WIDGET_GONK)
+  { PRESENTATION_DEVICE_PROVIDER_CATEGORY, "DisplayDeviceProvider", DISPLAY_DEVICE_PROVIDER_CONTRACT_ID },
+#endif
   { nullptr }
 };
 
 static const mozilla::Module kPresentationDeviceProviderModule = {
   mozilla::Module::kVersion,
   kPresentationDeviceProviderCIDs,
   kPresentationDeviceProviderContracts,
   kPresentationDeviceProviderCategories
--- a/dom/presentation/provider/moz.build
+++ b/dom/presentation/provider/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXTRA_COMPONENTS += [
     'BuiltinProviders.manifest',
     'TCPPresentationServer.js'
 ]
 
 UNIFIED_SOURCES += [
+    'DisplayDeviceProvider.cpp',
     'MulticastDNSDeviceProvider.cpp',
     'PresentationDeviceProviderModule.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']: