mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
47a9fb5513
This adds context to `CloseAlert()` such that explicitly closing the notification e.g. `notification.close()` can be differentiated from a tab or window implicitly closing the notification. This is necessary as we want notifications to persist after a tab or window is closed for Windows. This change in behavior is necessary to match user expectations. Users expect notifications to persist in the system tray and do not expect notifications to be lost due to a tab being closed. The content of the message is more important than the interaction in that lens. This change is also necessary for parity with Chrome. Differential Revision: https://phabricator.services.mozilla.com/D161024
160 lines
4.6 KiB
C++
160 lines
4.6 KiB
C++
/* -*- Mode: c++; tab-width: 4; 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 "AndroidAlerts.h"
|
|
#include "mozilla/java/GeckoRuntimeWrappers.h"
|
|
#include "mozilla/java/WebNotificationWrappers.h"
|
|
#include "nsIPrincipal.h"
|
|
#include "nsIURI.h"
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
NS_IMPL_ISUPPORTS(AndroidAlerts, nsIAlertsService)
|
|
|
|
StaticAutoPtr<AndroidAlerts::ListenerMap> AndroidAlerts::sListenerMap;
|
|
nsTHashMap<nsStringHashKey, java::WebNotification::GlobalRef>
|
|
AndroidAlerts::mNotificationsMap;
|
|
|
|
NS_IMETHODIMP
|
|
AndroidAlerts::ShowAlertNotification(
|
|
const nsAString& aImageUrl, const nsAString& aAlertTitle,
|
|
const nsAString& aAlertText, bool aAlertTextClickable,
|
|
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
|
|
const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
|
|
const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
|
|
bool aRequireInteraction) {
|
|
MOZ_ASSERT_UNREACHABLE("Should be implemented by nsAlertsService.");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AndroidAlerts::ShowAlert(nsIAlertNotification* aAlert,
|
|
nsIObserver* aAlertListener) {
|
|
return ShowPersistentNotification(u""_ns, aAlert, aAlertListener);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AndroidAlerts::ShowPersistentNotification(const nsAString& aPersistentData,
|
|
nsIAlertNotification* aAlert,
|
|
nsIObserver* aAlertListener) {
|
|
// nsAlertsService disables our alerts backend if we ever return failure
|
|
// here. To keep the backend enabled, we always return NS_OK even if we
|
|
// encounter an error here.
|
|
nsresult rv;
|
|
|
|
nsAutoString imageUrl;
|
|
rv = aAlert->GetImageURL(imageUrl);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsAutoString title;
|
|
rv = aAlert->GetTitle(title);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsAutoString text;
|
|
rv = aAlert->GetText(text);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsAutoString cookie;
|
|
rv = aAlert->GetCookie(cookie);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsAutoString name;
|
|
rv = aAlert->GetName(name);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsAutoString lang;
|
|
rv = aAlert->GetLang(lang);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsAutoString dir;
|
|
rv = aAlert->GetDir(dir);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
bool requireInteraction;
|
|
rv = aAlert->GetRequireInteraction(&requireInteraction);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
rv = aAlert->GetURI(getter_AddRefs(uri));
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsCString spec;
|
|
if (uri) {
|
|
rv = uri->GetDisplaySpec(spec);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
}
|
|
|
|
bool silent;
|
|
rv = aAlert->GetSilent(&silent);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
bool privateBrowsing;
|
|
rv = aAlert->GetInPrivateBrowsing(&privateBrowsing);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
nsTArray<uint32_t> vibrate;
|
|
rv = aAlert->GetVibrate(vibrate);
|
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
|
|
|
if (aPersistentData.IsEmpty() && aAlertListener) {
|
|
if (!sListenerMap) {
|
|
sListenerMap = new ListenerMap();
|
|
}
|
|
// This will remove any observers already registered for this name.
|
|
sListenerMap->InsertOrUpdate(name, aAlertListener);
|
|
}
|
|
|
|
java::WebNotification::LocalRef notification = notification->New(
|
|
title, name, cookie, text, imageUrl, dir, lang, requireInteraction, spec,
|
|
silent, privateBrowsing, jni::IntArray::From(vibrate));
|
|
java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
|
|
if (runtime != NULL) {
|
|
runtime->NotifyOnShow(notification);
|
|
}
|
|
mNotificationsMap.InsertOrUpdate(name, notification);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AndroidAlerts::CloseAlert(const nsAString& aAlertName, bool aContextClosed) {
|
|
java::WebNotification::LocalRef notification =
|
|
mNotificationsMap.Get(aAlertName);
|
|
if (!notification) {
|
|
return NS_OK;
|
|
}
|
|
|
|
java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
|
|
if (runtime != NULL) {
|
|
runtime->NotifyOnClose(notification);
|
|
}
|
|
mNotificationsMap.Remove(aAlertName);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void AndroidAlerts::NotifyListener(const nsAString& aName, const char* aTopic,
|
|
const char16_t* aCookie) {
|
|
if (!sListenerMap) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIObserver> listener = sListenerMap->Get(aName);
|
|
if (!listener) {
|
|
return;
|
|
}
|
|
|
|
listener->Observe(nullptr, aTopic, aCookie);
|
|
|
|
if ("alertfinished"_ns.Equals(aTopic)) {
|
|
sListenerMap->Remove(aName);
|
|
mNotificationsMap.Remove(aName);
|
|
}
|
|
}
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|