Bug 1069230 - Presentation API implementation. Part 2 - Presentation service and listeners. r=smaug
authorSean Lin <selin@mozilla.com>
Wed, 25 Mar 2015 19:47:56 +0800
changeset 288282 6dfe03f1db49962abe61328dfcdb81fe62055227
parent 288281 91124e7dba5fe7541d8d9d290bc8a963426bda17
child 288283 ae8604b64e921e30229a9703516dbabf5a1bf534
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1069230
milestone42.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 1069230 - Presentation API implementation. Part 2 - Presentation service and listeners. r=smaug
dom/presentation/PresentationService.cpp
dom/presentation/PresentationService.h
dom/presentation/PresentationSessionInfo.h
dom/presentation/interfaces/moz.build
dom/presentation/interfaces/nsIPresentationListener.idl
dom/presentation/interfaces/nsIPresentationService.idl
dom/presentation/moz.build
layout/build/nsLayoutModule.cpp
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationService.cpp
@@ -0,0 +1,174 @@
+/* -*- 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 "mozilla/Services.h"
+#include "nsIObserverService.h"
+#include "nsIPresentationListener.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "PresentationService.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS(PresentationService, nsIPresentationService, nsIObserver)
+
+PresentationService::PresentationService()
+{
+}
+
+PresentationService::~PresentationService()
+{
+}
+
+bool
+PresentationService::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return false;
+  }
+
+  // TODO: Add observers and get available devices.
+
+  return true;
+}
+
+NS_IMETHODIMP
+PresentationService::Observe(nsISupports* aSubject,
+                             const char* aTopic,
+                             const char16_t* aData)
+{
+  // TODO: Handle device availability changes can call |NotifyAvailableChange|.
+
+  return NS_OK;
+}
+
+void
+PresentationService::NotifyAvailableChange(bool aIsAvailable)
+{
+  nsTObserverArray<nsCOMPtr<nsIPresentationListener> >::ForwardIterator iter(mListeners);
+  while (iter.HasMore()) {
+    nsCOMPtr<nsIPresentationListener> listener = iter.GetNext();
+    NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aIsAvailable)));
+  }
+}
+
+NS_IMETHODIMP
+PresentationService::StartSession(const nsAString& aUrl,
+                                  const nsAString& aSessionId,
+                                  const nsAString& aOrigin,
+                                  nsIPresentationServiceCallback* aCallback)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aCallback);
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+
+  // TODO: Reply the callback.
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::SendSessionMessage(const nsAString& aSessionId,
+                                        nsIInputStream* aStream)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aStream);
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+
+  // TODO: Send input stream to the session.
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::Terminate(const nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+
+  // TODO: Terminate the session.
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::RegisterListener(nsIPresentationListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (NS_WARN_IF(mListeners.Contains(aListener))) {
+    return NS_OK;
+  }
+
+  mListeners.AppendElement(aListener);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::UnregisterListener(nsIPresentationListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mListeners.RemoveElement(aListener);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::RegisterSessionListener(const nsAString& aSessionId,
+                                             nsIPresentationSessionListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aListener);
+
+  PresentationSessionInfo* info = mSessionInfo.Get(aSessionId);
+  if (NS_WARN_IF(!info)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  info->SetListener(aListener);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::UnregisterSessionListener(const nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  PresentationSessionInfo* info = mSessionInfo.Get(aSessionId);
+  if (info) {
+    info->SetListener(nullptr);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::GetExistentSessionIdAtLaunch(nsAString& aSessionId)
+{
+  // TODO: Return the value based on it's a sender or a receiver.
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationService::NotifyReceiverReady(const nsAString& aSessionId)
+{
+  // TODO: Notify the correspondent session info.
+
+  return NS_OK;
+}
+
+already_AddRefed<nsIPresentationService>
+NS_CreatePresentationService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIPresentationService> service = new PresentationService();
+  return NS_WARN_IF(!static_cast<PresentationService*>(service.get())->Init()) ?
+         nullptr : service.forget();
+}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationService.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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_PresentationService_h
+#define mozilla_dom_PresentationService_h
+
+#include "nsClassHashtable.h"
+#include "nsCOMPtr.h"
+#include "nsIObserver.h"
+#include "nsTObserverArray.h"
+#include "PresentationSessionInfo.h"
+
+namespace mozilla {
+namespace dom {
+
+class PresentationService final : public nsIPresentationService
+                                , public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  NS_DECL_NSIPRESENTATIONSERVICE
+
+  PresentationService();
+  bool Init();
+
+private:
+  ~PresentationService();
+  void NotifyAvailableChange(bool aIsAvailable);
+
+  nsClassHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfo;
+  nsTObserverArray<nsCOMPtr<nsIPresentationListener> > mListeners;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationService_h
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationSessionInfo.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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_PresentationSessionInfo_h
+#define mozilla_dom_PresentationSessionInfo_h
+
+#include "mozilla/nsRefPtr.h"
+#include "nsCOMPtr.h"
+#include "nsIPresentationListener.h"
+#include "nsIPresentationService.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+
+class PresentationSessionInfo
+{
+public:
+  PresentationSessionInfo(const nsAString& aUrl,
+                          const nsAString& aSessionId,
+                          nsIPresentationServiceCallback* aCallback)
+    : mUrl(aUrl)
+    , mSessionId(aSessionId)
+    , mCallback(aCallback)
+  {
+    MOZ_ASSERT(!mUrl.IsEmpty());
+    MOZ_ASSERT(!mSessionId.IsEmpty());
+  }
+
+  const nsAString& GetUrl() const
+  {
+    return mUrl;
+  }
+
+  const nsAString& GetSessionId() const
+  {
+    return mSessionId;
+  }
+
+  void SetCallback(nsIPresentationServiceCallback* aCallback)
+  {
+    mCallback = aCallback;
+  }
+
+  void SetListener(nsIPresentationSessionListener* aListener)
+  {
+    mListener = aListener;
+  }
+
+private:
+  nsString mUrl;
+  nsString mSessionId;
+  nsCOMPtr<nsIPresentationServiceCallback> mCallback;
+  nsCOMPtr<nsIPresentationSessionListener> mListener;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationSessionInfo_h
--- a/dom/presentation/interfaces/moz.build
+++ b/dom/presentation/interfaces/moz.build
@@ -5,14 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIPresentationControlChannel.idl',
     'nsIPresentationDevice.idl',
     'nsIPresentationDeviceManager.idl',
     'nsIPresentationDevicePrompt.idl',
     'nsIPresentationDeviceProvider.idl',
+    'nsIPresentationListener.idl',
+    'nsIPresentationService.idl',
     'nsIPresentationSessionRequest.idl',
     'nsITCPPresentationServer.idl',
 ]
 
 XPIDL_MODULE = 'dom_presentation'
 
new file mode 100644
--- /dev/null
+++ b/dom/presentation/interfaces/nsIPresentationListener.idl
@@ -0,0 +1,34 @@
+/* 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 "nsISupports.idl"
+
+[scriptable, uuid(0105f837-4279-4715-9d5b-2dc3f8b65353)]
+interface nsIPresentationListener : nsISupports
+{
+  /*
+   * Called when device availability changes.
+   */
+  void notifyAvailableChange(in bool available);
+};
+
+[scriptable, uuid(3b9ae71f-2905-4969-9117-101627c1c2ea)]
+interface nsIPresentationSessionListener : nsISupports
+{
+  const unsigned short STATE_CONNECTED = 0;
+  const unsigned short STATE_DISCONNECTED = 1;
+  const unsigned short STATE_TERMINATED = 2;
+
+  /*
+   * Called when session state changes.
+   */
+  void notifyStateChange(in DOMString sessionId,
+                         in unsigned short state);
+
+  /*
+   * Called when receive messages.
+   */
+  void notifyMessage(in DOMString sessionId,
+                     in ACString data);
+};
new file mode 100644
--- /dev/null
+++ b/dom/presentation/interfaces/nsIPresentationService.idl
@@ -0,0 +1,112 @@
+/* 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 "nsISupports.idl"
+
+interface nsIInputStream;
+interface nsIPresentationListener;
+interface nsIPresentationSessionListener;
+
+%{C++
+#define PRESENTATION_SERVICE_CID \
+  { 0x1d9bb10c, 0xc0ab, 0x4fe8, \
+    { 0x9e, 0x4f, 0x40, 0x58, 0xb8, 0x51, 0x98, 0x32 } }
+#define PRESENTATION_SERVICE_CONTRACTID \
+  "@mozilla.org/presentation/presentationservice;1"
+%}
+
+[scriptable, uuid(12073206-0065-4b10-9488-a6eb9b23e65b)]
+interface nsIPresentationServiceCallback : nsISupports
+{
+  /*
+   * Called when the operation succeeds.
+   */
+  void notifySuccess();
+
+  /*
+   * Called when the operation fails.
+   *
+   * @param error: error message.
+   */
+  void notifyError(in nsresult error);
+};
+
+[scriptable, uuid(5801efd9-9dba-4af7-8be9-8fc97c2d54a6)]
+interface nsIPresentationService : nsISupports
+{
+  /*
+   * Start a new presentation session and display a prompt box which asks users
+   * to select a device.
+   *
+   * @param url: The url of presenting page.
+   * @param sessionId: An ID to identify presentation session.
+   * @param origin: The url of requesting page.
+   * @param callback: Invoke the callback when the operation is completed.
+   *                  NotifySuccess() is called with |id| if a session is
+   *                  established successfully with the selected device.
+   *                  Otherwise, NotifyError() is called with a error message.
+   */
+  void startSession(in DOMString url,
+                    in DOMString sessionId,
+                    in DOMString origin,
+                    in nsIPresentationServiceCallback callback);
+
+  /*
+   * Send the message wrapped with an input stream to the session.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   * @param stream: The message is converted to an input stream.
+   */
+  void sendSessionMessage(in DOMString sessionId,
+                          in nsIInputStream stream);
+
+  /*
+   * Terminate the session.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   */
+  void terminate(in DOMString sessionId);
+
+  /*
+   * Register a listener. Must be called from the main thread.
+   *
+   * @param listener: The listener to register.
+   */
+  void registerListener(in nsIPresentationListener listener);
+
+  /*
+   * Unregister a listener. Must be called from the main thread.
+   * @param listener: The listener to unregister.
+   */
+  void unregisterListener(in nsIPresentationListener listener);
+
+  /*
+   * Register a session listener. Must be called from the main thread.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   * @param listener: The listener to register.
+   */
+  void registerSessionListener(in DOMString sessionId,
+                               in nsIPresentationSessionListener listener);
+
+  /*
+   * Unregister a session listener. Must be called from the main thread.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   */
+  void unregisterSessionListener(in DOMString sessionId);
+
+  /*
+   * Check if the presentation instance has an existent session ID at launch.
+   * An empty string is returned at sender side; non-empty at receiver side.
+   */
+  DOMString getExistentSessionIdAtLaunch();
+
+  /*
+   * Notify the receiver page is ready for presentation use.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   */
+  void notifyReceiverReady(in DOMString sessionId);
+};
--- a/dom/presentation/moz.build
+++ b/dom/presentation/moz.build
@@ -7,22 +7,25 @@
 DIRS += ['interfaces', 'provider']
 
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
 
 EXPORTS.mozilla.dom += [
     'Presentation.h',
     'PresentationDeviceManager.h',
+    'PresentationService.h',
     'PresentationSession.h',
+    'PresentationSessionInfo.h',
 ]
 
 UNIFIED_SOURCES += [
     'Presentation.cpp',
     'PresentationDeviceManager.cpp',
+    'PresentationService.cpp',
     'PresentationSession.cpp',
     'PresentationSessionRequest.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'PresentationDeviceInfoManager.js',
     'PresentationDeviceInfoManager.manifest',
 ]
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -235,16 +235,17 @@ static void Shutdown();
 
 #include "mozilla/dom/DataStoreService.h"
 
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/alarm/AlarmHalService.h"
 #include "mozilla/dom/time/TimeService.h"
 #include "StreamingProtocolService.h"
 
+#include "nsIPresentationService.h"
 #include "nsITelephonyService.h"
 #include "nsIVoicemailService.h"
 
 #include "mozilla/dom/FakeTVService.h"
 #include "mozilla/dom/TVServiceFactory.h"
 #include "mozilla/dom/TVTypes.h"
 #include "nsITVService.h"
 
@@ -288,16 +289,18 @@ using mozilla::gmp::GeckoMediaPluginServ
 #define TRANSFORMIIX_NODESET_CONTRACTID \
 "@mozilla.org/transformiix-nodeset;1"
 
 // PresentationDeviceManager
 /* e1e79dec-4085-4994-ac5b-744b016697e6 */
 #define PRESENTATION_DEVICE_MANAGER_CID \
 { 0xe1e79dec, 0x4085, 0x4994, { 0xac, 0x5b, 0x74, 0x4b, 0x01, 0x66, 0x97, 0xe6 } }
 
+already_AddRefed<nsIPresentationService> NS_CreatePresentationService();
+
 // Factory Constructor
 NS_GENERIC_FACTORY_CONSTRUCTOR(txMozillaXSLTProcessor)
 NS_GENERIC_FACTORY_CONSTRUCTOR(XPathEvaluator)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(txNodeSetAdaptor, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMSerializer)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsXMLHttpRequest, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDOMFileReader, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormData)
@@ -396,16 +399,18 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
 NS_GENERIC_FACTORY_CONSTRUCTOR(TVTunerData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TVChannelData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TVProgramData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationDeviceManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TextInputProcessor)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(FakeInputPortService,
                                          InputPortServiceFactory::CreateFakeInputPortService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(InputPortData)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPresentationService,
+                                         NS_CreatePresentationService)
 //-----------------------------------------------------------------------------
 
 static bool gInitialized = false;
 
 // Perform our one-time intialization for this module
 
 // static
 nsresult
@@ -852,16 +857,17 @@ NS_DEFINE_NAMED_CID(TV_TUNER_DATA_CID);
 NS_DEFINE_NAMED_CID(TV_CHANNEL_DATA_CID);
 NS_DEFINE_NAMED_CID(TV_PROGRAM_DATA_CID);
 
 NS_DEFINE_NAMED_CID(FAKE_INPUTPORT_SERVICE_CID);
 NS_DEFINE_NAMED_CID(INPUTPORT_DATA_CID);
 
 NS_DEFINE_NAMED_CID(GECKO_MEDIA_PLUGIN_SERVICE_CID);
 
+NS_DEFINE_NAMED_CID(PRESENTATION_SERVICE_CID);
 NS_DEFINE_NAMED_CID(PRESENTATION_DEVICE_MANAGER_CID);
 
 NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID);
 
 static nsresult
 CreateWindowCommandTableConstructor(nsISupports *aOuter,
                                     REFNSIID aIID, void **aResult)
 {
@@ -1150,16 +1156,17 @@ static const mozilla::Module::CIDEntry k
 #endif
   { &kTELEPHONY_SERVICE_CID, false, nullptr, nsITelephonyServiceConstructor },
   { &kNS_MOBILE_CONNECTION_SERVICE_CID, false, NULL, nsIMobileConnectionServiceConstructor },
   { &kNS_VOICEMAIL_SERVICE_CID, false, nullptr, nsIVoicemailServiceConstructor },
   { &kFAKE_TV_SERVICE_CID, false, nullptr, FakeTVServiceConstructor },
   { &kTV_TUNER_DATA_CID, false, nullptr, TVTunerDataConstructor },
   { &kTV_CHANNEL_DATA_CID, false, nullptr, TVChannelDataConstructor },
   { &kTV_PROGRAM_DATA_CID, false, nullptr, TVProgramDataConstructor },
+  { &kPRESENTATION_SERVICE_CID, false, nullptr, nsIPresentationServiceConstructor },
   { &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor },
   { &kTEXT_INPUT_PROCESSOR_CID, false, nullptr, TextInputProcessorConstructor },
   { &kFAKE_INPUTPORT_SERVICE_CID, false, nullptr, FakeInputPortServiceConstructor },
   { &kINPUTPORT_DATA_CID, false, nullptr, InputPortDataConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
@@ -1319,16 +1326,17 @@ static const mozilla::Module::ContractID
   { TELEPHONY_SERVICE_CONTRACTID, &kTELEPHONY_SERVICE_CID },
   { FAKE_TV_SERVICE_CONTRACTID, &kFAKE_TV_SERVICE_CID },
   { TV_TUNER_DATA_CONTRACTID, &kTV_TUNER_DATA_CID },
   { TV_CHANNEL_DATA_CONTRACTID, &kTV_CHANNEL_DATA_CID },
   { TV_PROGRAM_DATA_CONTRACTID, &kTV_PROGRAM_DATA_CID },
   { "@mozilla.org/gecko-media-plugin-service;1",  &kGECKO_MEDIA_PLUGIN_SERVICE_CID },
   { NS_MOBILE_CONNECTION_SERVICE_CONTRACTID, &kNS_MOBILE_CONNECTION_SERVICE_CID },
   { NS_VOICEMAIL_SERVICE_CONTRACTID, &kNS_VOICEMAIL_SERVICE_CID },
+  { PRESENTATION_SERVICE_CONTRACTID, &kPRESENTATION_SERVICE_CID },
   { PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID },
   { "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID },
   { FAKE_INPUTPORT_SERVICE_CONTRACTID, &kFAKE_INPUTPORT_SERVICE_CID },
   { INPUTPORT_DATA_CONTRACTID, &kINPUTPORT_DATA_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
@@ -1348,16 +1356,17 @@ static const mozilla::Module::CategoryEn
   CONTENTDLF_CATEGORIES
 #ifdef MOZ_WIDGET_GONK
   { "profile-after-change", "Gonk System Worker Manager", SYSTEMWORKERMANAGER_CONTRACTID },
 #endif
 #ifdef MOZ_B2G_BT
   { "profile-after-change", "Bluetooth Service", BLUETOOTHSERVICE_CONTRACTID },
 #endif
   { "profile-after-change", "PresentationDeviceManager", PRESENTATION_DEVICE_MANAGER_CONTRACTID },
+  { "profile-after-change", "PresentationService", PRESENTATION_SERVICE_CONTRACTID },
   { "idle-daily", "ServiceWorker Periodic Updater", SERVICEWORKERPERIODICUPDATER_CONTRACTID },
   { nullptr }
 };
 
 static void
 LayoutModuleDtor()
 {
   Shutdown();