123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /* -*- Mode: C++; tab-width: 8; 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/dom/DesktopNotification.h"
- #include "mozilla/dom/DesktopNotificationBinding.h"
- #include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
- #include "mozilla/dom/ToJSValue.h"
- #include "nsComponentManagerUtils.h"
- #include "nsContentPermissionHelper.h"
- #include "nsXULAppAPI.h"
- #include "mozilla/dom/PBrowserChild.h"
- #include "mozilla/Preferences.h"
- #include "nsGlobalWindow.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsServiceManagerUtils.h"
- #include "PermissionMessageUtils.h"
- #include "nsILoadContext.h"
- namespace mozilla {
- namespace dom {
- /*
- * Simple Request
- */
- class DesktopNotificationRequest : public nsIContentPermissionRequest
- , public Runnable
- {
- virtual ~DesktopNotificationRequest()
- {
- }
- nsCOMPtr<nsIContentPermissionRequester> mRequester;
- public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSICONTENTPERMISSIONREQUEST
- explicit DesktopNotificationRequest(DesktopNotification* aNotification)
- : mDesktopNotification(aNotification)
- {
- mRequester = new nsContentPermissionRequester(mDesktopNotification->GetOwner());
- }
- NS_IMETHOD Run() override
- {
- nsCOMPtr<nsPIDOMWindowInner> window = mDesktopNotification->GetOwner();
- nsContentPermissionUtils::AskPermission(this, window);
- return NS_OK;
- }
- RefPtr<DesktopNotification> mDesktopNotification;
- };
- /* ------------------------------------------------------------------------ */
- /* AlertServiceObserver */
- /* ------------------------------------------------------------------------ */
- NS_IMPL_ISUPPORTS(AlertServiceObserver, nsIObserver)
- /* ------------------------------------------------------------------------ */
- /* DesktopNotification */
- /* ------------------------------------------------------------------------ */
- uint32_t DesktopNotification::sCount = 0;
- nsresult
- DesktopNotification::PostDesktopNotification()
- {
- if (!mObserver) {
- mObserver = new AlertServiceObserver(this);
- }
- nsCOMPtr<nsIAlertsService> alerts = do_GetService("@mozilla.org/alerts-service;1");
- if (!alerts) {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- // Generate a unique name (which will also be used as a cookie) because
- // the nsIAlertsService will coalesce notifications with the same name.
- // In the case of IPC, the parent process will use the cookie to map
- // to nsIObservers, thus cookies must be unique to differentiate observers.
- nsString uniqueName = NS_LITERAL_STRING("desktop-notification:");
- uniqueName.AppendInt(sCount++);
- nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
- if (!owner) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIDocument> doc = owner->GetDoc();
- nsIPrincipal* principal = doc->NodePrincipal();
- nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
- bool inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
- nsCOMPtr<nsIAlertNotification> alert =
- do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
- NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
- nsresult rv = alert->Init(uniqueName, mIconURL, mTitle,
- mDescription,
- true,
- uniqueName,
- NS_LITERAL_STRING("auto"),
- EmptyString(),
- EmptyString(),
- principal,
- inPrivateBrowsing,
- false /* requireInteraction */);
- NS_ENSURE_SUCCESS(rv, rv);
- return alerts->ShowAlert(alert, mObserver);
- }
- DesktopNotification::DesktopNotification(const nsAString & title,
- const nsAString & description,
- const nsAString & iconURL,
- nsPIDOMWindowInner* aWindow,
- nsIPrincipal* principal)
- : DOMEventTargetHelper(aWindow)
- , mTitle(title)
- , mDescription(description)
- , mIconURL(iconURL)
- , mPrincipal(principal)
- , mAllow(false)
- , mShowHasBeenCalled(false)
- {
- if (Preferences::GetBool("notification.disabled", false)) {
- return;
- }
- // If we are in testing mode (running mochitests, for example)
- // and we are suppose to allow requests, then just post an allow event.
- if (Preferences::GetBool("notification.prompt.testing", false) &&
- Preferences::GetBool("notification.prompt.testing.allow", true)) {
- mAllow = true;
- }
- }
- void
- DesktopNotification::Init()
- {
- RefPtr<DesktopNotificationRequest> request = new DesktopNotificationRequest(this);
- NS_DispatchToMainThread(request);
- }
- DesktopNotification::~DesktopNotification()
- {
- if (mObserver) {
- mObserver->Disconnect();
- }
- }
- void
- DesktopNotification::DispatchNotificationEvent(const nsString& aName)
- {
- if (NS_FAILED(CheckInnerWindowCorrectness())) {
- return;
- }
- RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
- // it doesn't bubble, and it isn't cancelable
- event->InitEvent(aName, false, false);
- event->SetTrusted(true);
- DispatchDOMEvent(nullptr, event, nullptr, nullptr);
- }
- nsresult
- DesktopNotification::SetAllow(bool aAllow)
- {
- mAllow = aAllow;
- // if we have called Show() already, lets go ahead and post a notification
- if (mShowHasBeenCalled && aAllow) {
- return PostDesktopNotification();
- }
- return NS_OK;
- }
- void
- DesktopNotification::HandleAlertServiceNotification(const char *aTopic)
- {
- if (NS_FAILED(CheckInnerWindowCorrectness())) {
- return;
- }
- if (!strcmp("alertclickcallback", aTopic)) {
- DispatchNotificationEvent(NS_LITERAL_STRING("click"));
- } else if (!strcmp("alertfinished", aTopic)) {
- DispatchNotificationEvent(NS_LITERAL_STRING("close"));
- }
- }
- void
- DesktopNotification::Show(ErrorResult& aRv)
- {
- mShowHasBeenCalled = true;
- if (!mAllow) {
- return;
- }
- aRv = PostDesktopNotification();
- }
- JSObject*
- DesktopNotification::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return DesktopNotificationBinding::Wrap(aCx, this, aGivenProto);
- }
- /* ------------------------------------------------------------------------ */
- /* DesktopNotificationCenter */
- /* ------------------------------------------------------------------------ */
- NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(DesktopNotificationCenter)
- NS_IMPL_CYCLE_COLLECTING_ADDREF(DesktopNotificationCenter)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(DesktopNotificationCenter)
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DesktopNotificationCenter)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- already_AddRefed<DesktopNotification>
- DesktopNotificationCenter::CreateNotification(const nsAString& aTitle,
- const nsAString& aDescription,
- const nsAString& aIconURL)
- {
- MOZ_ASSERT(mOwner);
- RefPtr<DesktopNotification> notification =
- new DesktopNotification(aTitle,
- aDescription,
- aIconURL,
- mOwner,
- mPrincipal);
- notification->Init();
- return notification.forget();
- }
- JSObject*
- DesktopNotificationCenter::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return DesktopNotificationCenterBinding::Wrap(aCx, this, aGivenProto);
- }
- /* ------------------------------------------------------------------------ */
- /* DesktopNotificationRequest */
- /* ------------------------------------------------------------------------ */
- NS_IMPL_ISUPPORTS_INHERITED(DesktopNotificationRequest, Runnable,
- nsIContentPermissionRequest)
- NS_IMETHODIMP
- DesktopNotificationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
- {
- if (!mDesktopNotification) {
- return NS_ERROR_NOT_INITIALIZED;
- }
- NS_IF_ADDREF(*aRequestingPrincipal = mDesktopNotification->mPrincipal);
- return NS_OK;
- }
- NS_IMETHODIMP
- DesktopNotificationRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
- {
- if (!mDesktopNotification) {
- return NS_ERROR_NOT_INITIALIZED;
- }
- NS_IF_ADDREF(*aRequestingWindow = mDesktopNotification->GetOwner());
- return NS_OK;
- }
- NS_IMETHODIMP
- DesktopNotificationRequest::GetElement(nsIDOMElement * *aElement)
- {
- NS_ENSURE_ARG_POINTER(aElement);
- *aElement = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- DesktopNotificationRequest::Cancel()
- {
- nsresult rv = mDesktopNotification->SetAllow(false);
- mDesktopNotification = nullptr;
- return rv;
- }
- NS_IMETHODIMP
- DesktopNotificationRequest::Allow(JS::HandleValue aChoices)
- {
- MOZ_ASSERT(aChoices.isUndefined());
- nsresult rv = mDesktopNotification->SetAllow(true);
- mDesktopNotification = nullptr;
- return rv;
- }
- NS_IMETHODIMP
- DesktopNotificationRequest::GetRequester(nsIContentPermissionRequester** aRequester)
- {
- NS_ENSURE_ARG_POINTER(aRequester);
- nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
- requester.forget(aRequester);
- return NS_OK;
- }
- NS_IMETHODIMP
- DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
- {
- nsTArray<nsString> emptyOptions;
- return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
- NS_LITERAL_CSTRING("unused"),
- emptyOptions,
- aTypes);
- }
- } // namespace dom
- } // namespace mozilla
|