1 /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "AndroidAlerts.h"
7 #include "mozilla/java/GeckoRuntimeWrappers.h"
8 #include "mozilla/java/WebNotificationWrappers.h"
9 #include "nsAlertsUtils.h"
10 
11 namespace mozilla {
12 namespace widget {
13 
14 NS_IMPL_ISUPPORTS(AndroidAlerts, nsIAlertsService)
15 
16 StaticAutoPtr<AndroidAlerts::ListenerMap> AndroidAlerts::sListenerMap;
17 nsDataHashtable<nsStringHashKey, java::WebNotification::GlobalRef>
18     AndroidAlerts::mNotificationsMap;
19 
20 NS_IMETHODIMP
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)21 AndroidAlerts::ShowAlertNotification(
22     const nsAString& aImageUrl, const nsAString& aAlertTitle,
23     const nsAString& aAlertText, bool aAlertTextClickable,
24     const nsAString& aAlertCookie, nsIObserver* aAlertListener,
25     const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
26     const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
27     bool aRequireInteraction) {
28   MOZ_ASSERT_UNREACHABLE("Should be implemented by nsAlertsService.");
29   return NS_ERROR_NOT_IMPLEMENTED;
30 }
31 
32 NS_IMETHODIMP
ShowAlert(nsIAlertNotification * aAlert,nsIObserver * aAlertListener)33 AndroidAlerts::ShowAlert(nsIAlertNotification* aAlert,
34                          nsIObserver* aAlertListener) {
35   return ShowPersistentNotification(EmptyString(), aAlert, aAlertListener);
36 }
37 
38 NS_IMETHODIMP
ShowPersistentNotification(const nsAString & aPersistentData,nsIAlertNotification * aAlert,nsIObserver * aAlertListener)39 AndroidAlerts::ShowPersistentNotification(const nsAString& aPersistentData,
40                                           nsIAlertNotification* aAlert,
41                                           nsIObserver* aAlertListener) {
42   // nsAlertsService disables our alerts backend if we ever return failure
43   // here. To keep the backend enabled, we always return NS_OK even if we
44   // encounter an error here.
45   nsresult rv;
46 
47   nsAutoString imageUrl;
48   rv = aAlert->GetImageURL(imageUrl);
49   NS_ENSURE_SUCCESS(rv, NS_OK);
50 
51   nsAutoString title;
52   rv = aAlert->GetTitle(title);
53   NS_ENSURE_SUCCESS(rv, NS_OK);
54 
55   nsAutoString text;
56   rv = aAlert->GetText(text);
57   NS_ENSURE_SUCCESS(rv, NS_OK);
58 
59   nsAutoString cookie;
60   rv = aAlert->GetCookie(cookie);
61   NS_ENSURE_SUCCESS(rv, NS_OK);
62 
63   nsAutoString name;
64   rv = aAlert->GetName(name);
65   NS_ENSURE_SUCCESS(rv, NS_OK);
66 
67   nsAutoString lang;
68   rv = aAlert->GetLang(lang);
69   NS_ENSURE_SUCCESS(rv, NS_OK);
70 
71   nsAutoString dir;
72   rv = aAlert->GetDir(dir);
73   NS_ENSURE_SUCCESS(rv, NS_OK);
74 
75   bool requireInteraction;
76   rv = aAlert->GetRequireInteraction(&requireInteraction);
77   NS_ENSURE_SUCCESS(rv, NS_OK);
78 
79   nsCOMPtr<nsIPrincipal> principal;
80   rv = aAlert->GetPrincipal(getter_AddRefs(principal));
81   NS_ENSURE_SUCCESS(rv, NS_OK);
82 
83   nsAutoString host;
84   nsAlertsUtils::GetSourceHostPort(principal, host);
85 
86   if (aPersistentData.IsEmpty() && aAlertListener) {
87     if (!sListenerMap) {
88       sListenerMap = new ListenerMap();
89     }
90     // This will remove any observers already registered for this name.
91     sListenerMap->Put(name, aAlertListener);
92   }
93 
94   java::WebNotification::LocalRef notification = notification->New(
95       title, name, cookie, text, imageUrl, dir, lang, requireInteraction);
96   java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
97   if (runtime != NULL) {
98     runtime->NotifyOnShow(notification);
99   }
100   mNotificationsMap.Put(name, notification);
101 
102   return NS_OK;
103 }
104 
105 NS_IMETHODIMP
CloseAlert(const nsAString & aAlertName,nsIPrincipal * aPrincipal)106 AndroidAlerts::CloseAlert(const nsAString& aAlertName,
107                           nsIPrincipal* aPrincipal) {
108   java::WebNotification::LocalRef notification =
109       mNotificationsMap.Get(aAlertName);
110   if (!notification) {
111     return NS_OK;
112   }
113 
114   java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
115   if (runtime != NULL) {
116     runtime->NotifyOnClose(notification);
117   }
118   mNotificationsMap.Remove(aAlertName);
119 
120   return NS_OK;
121 }
122 
NotifyListener(const nsAString & aName,const char * aTopic,const char16_t * aCookie)123 void AndroidAlerts::NotifyListener(const nsAString& aName, const char* aTopic,
124                                    const char16_t* aCookie) {
125   if (!sListenerMap) {
126     return;
127   }
128 
129   nsCOMPtr<nsIObserver> listener = sListenerMap->Get(aName);
130   if (!listener) {
131     return;
132   }
133 
134   listener->Observe(nullptr, aTopic, aCookie);
135 
136   if (NS_LITERAL_CSTRING("alertfinished").Equals(aTopic)) {
137     sListenerMap->Remove(aName);
138     mNotificationsMap.Remove(aName);
139   }
140 }
141 
142 }  // namespace widget
143 }  // namespace mozilla
144