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 "nsIPrincipal.h"
10 #include "nsIURI.h"
11 
12 namespace mozilla {
13 namespace widget {
14 
15 NS_IMPL_ISUPPORTS(AndroidAlerts, nsIAlertsService)
16 
17 StaticAutoPtr<AndroidAlerts::ListenerMap> AndroidAlerts::sListenerMap;
18 nsTHashMap<nsStringHashKey, java::WebNotification::GlobalRef>
19     AndroidAlerts::mNotificationsMap;
20 
21 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)22 AndroidAlerts::ShowAlertNotification(
23     const nsAString& aImageUrl, const nsAString& aAlertTitle,
24     const nsAString& aAlertText, bool aAlertTextClickable,
25     const nsAString& aAlertCookie, nsIObserver* aAlertListener,
26     const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
27     const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
28     bool aRequireInteraction) {
29   MOZ_ASSERT_UNREACHABLE("Should be implemented by nsAlertsService.");
30   return NS_ERROR_NOT_IMPLEMENTED;
31 }
32 
33 NS_IMETHODIMP
ShowAlert(nsIAlertNotification * aAlert,nsIObserver * aAlertListener)34 AndroidAlerts::ShowAlert(nsIAlertNotification* aAlert,
35                          nsIObserver* aAlertListener) {
36   return ShowPersistentNotification(u""_ns, aAlert, aAlertListener);
37 }
38 
39 NS_IMETHODIMP
ShowPersistentNotification(const nsAString & aPersistentData,nsIAlertNotification * aAlert,nsIObserver * aAlertListener)40 AndroidAlerts::ShowPersistentNotification(const nsAString& aPersistentData,
41                                           nsIAlertNotification* aAlert,
42                                           nsIObserver* aAlertListener) {
43   // nsAlertsService disables our alerts backend if we ever return failure
44   // here. To keep the backend enabled, we always return NS_OK even if we
45   // encounter an error here.
46   nsresult rv;
47 
48   nsAutoString imageUrl;
49   rv = aAlert->GetImageURL(imageUrl);
50   NS_ENSURE_SUCCESS(rv, NS_OK);
51 
52   nsAutoString title;
53   rv = aAlert->GetTitle(title);
54   NS_ENSURE_SUCCESS(rv, NS_OK);
55 
56   nsAutoString text;
57   rv = aAlert->GetText(text);
58   NS_ENSURE_SUCCESS(rv, NS_OK);
59 
60   nsAutoString cookie;
61   rv = aAlert->GetCookie(cookie);
62   NS_ENSURE_SUCCESS(rv, NS_OK);
63 
64   nsAutoString name;
65   rv = aAlert->GetName(name);
66   NS_ENSURE_SUCCESS(rv, NS_OK);
67 
68   nsAutoString lang;
69   rv = aAlert->GetLang(lang);
70   NS_ENSURE_SUCCESS(rv, NS_OK);
71 
72   nsAutoString dir;
73   rv = aAlert->GetDir(dir);
74   NS_ENSURE_SUCCESS(rv, NS_OK);
75 
76   bool requireInteraction;
77   rv = aAlert->GetRequireInteraction(&requireInteraction);
78   NS_ENSURE_SUCCESS(rv, NS_OK);
79 
80   nsCOMPtr<nsIURI> uri;
81   rv = aAlert->GetURI(getter_AddRefs(uri));
82   NS_ENSURE_SUCCESS(rv, NS_OK);
83 
84   nsCString spec;
85   if (uri) {
86     rv = uri->GetDisplaySpec(spec);
87     NS_ENSURE_SUCCESS(rv, NS_OK);
88   }
89 
90   bool silent;
91   rv = aAlert->GetSilent(&silent);
92   NS_ENSURE_SUCCESS(rv, NS_OK);
93 
94   nsTArray<uint32_t> vibrate;
95   rv = aAlert->GetVibrate(vibrate);
96   NS_ENSURE_SUCCESS(rv, NS_OK);
97 
98   if (aPersistentData.IsEmpty() && aAlertListener) {
99     if (!sListenerMap) {
100       sListenerMap = new ListenerMap();
101     }
102     // This will remove any observers already registered for this name.
103     sListenerMap->InsertOrUpdate(name, aAlertListener);
104   }
105 
106   java::WebNotification::LocalRef notification = notification->New(
107       title, name, cookie, text, imageUrl, dir, lang, requireInteraction, spec,
108       silent, jni::IntArray::From(vibrate));
109   java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
110   if (runtime != NULL) {
111     runtime->NotifyOnShow(notification);
112   }
113   mNotificationsMap.InsertOrUpdate(name, notification);
114 
115   return NS_OK;
116 }
117 
118 NS_IMETHODIMP
CloseAlert(const nsAString & aAlertName)119 AndroidAlerts::CloseAlert(const nsAString& aAlertName) {
120   java::WebNotification::LocalRef notification =
121       mNotificationsMap.Get(aAlertName);
122   if (!notification) {
123     return NS_OK;
124   }
125 
126   java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
127   if (runtime != NULL) {
128     runtime->NotifyOnClose(notification);
129   }
130   mNotificationsMap.Remove(aAlertName);
131 
132   return NS_OK;
133 }
134 
NotifyListener(const nsAString & aName,const char * aTopic,const char16_t * aCookie)135 void AndroidAlerts::NotifyListener(const nsAString& aName, const char* aTopic,
136                                    const char16_t* aCookie) {
137   if (!sListenerMap) {
138     return;
139   }
140 
141   nsCOMPtr<nsIObserver> listener = sListenerMap->Get(aName);
142   if (!listener) {
143     return;
144   }
145 
146   listener->Observe(nullptr, aTopic, aCookie);
147 
148   if ("alertfinished"_ns.Equals(aTopic)) {
149     sListenerMap->Remove(aName);
150     mNotificationsMap.Remove(aName);
151   }
152 }
153 
154 }  // namespace widget
155 }  // namespace mozilla
156