Rename DefinitelyProcessingUserGesture to DefinitelyProcessingNewUserGesture
[WebKit-https.git] / Source / WebKit2 / WebProcess / Notifications / WebNotificationManager.cpp
1 /*
2  * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebNotificationManager.h"
28
29 #include "WebPage.h"
30 #include "WebProcess.h"
31 #include "WebProcessCreationParameters.h"
32
33 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
34 #include "WebNotification.h"
35 #include "WebNotificationManagerMessages.h"
36 #include "WebNotificationManagerProxyMessages.h"
37 #include "WebPageProxyMessages.h"
38 #include <WebCore/Document.h>
39 #include <WebCore/Notification.h>
40 #include <WebCore/Page.h>
41 #include <WebCore/ScriptExecutionContext.h>
42 #include <WebCore/SecurityOrigin.h>
43 #include <WebCore/Settings.h>
44 #include <WebCore/UserGestureIndicator.h>
45 #endif
46
47 using namespace WebCore;
48
49 namespace WebKit {
50
51 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
52 static uint64_t generateNotificationID()
53 {
54     static uint64_t uniqueNotificationID = 1;
55     return uniqueNotificationID++;
56 }
57 #endif
58
59 const char* WebNotificationManager::supplementName()
60 {
61     return "WebNotificationManager";
62 }
63
64 WebNotificationManager::WebNotificationManager(WebProcess* process)
65     : m_process(process)
66 {
67 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
68     m_process->addMessageReceiver(Messages::WebNotificationManager::messageReceiverName(), this);
69 #endif
70 }
71
72 WebNotificationManager::~WebNotificationManager()
73 {
74 }
75
76 void WebNotificationManager::initialize(const WebProcessCreationParameters& parameters)
77 {
78 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
79     m_permissionsMap = parameters.notificationPermissions;
80 #else
81     UNUSED_PARAM(parameters);
82 #endif
83 }
84
85 void WebNotificationManager::didUpdateNotificationDecision(const String& originString, bool allowed)
86 {
87 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
88     m_permissionsMap.set(originString, allowed);
89 #else
90     UNUSED_PARAM(originString);
91     UNUSED_PARAM(allowed);
92 #endif
93 }
94
95 void WebNotificationManager::didRemoveNotificationDecisions(const Vector<String>& originStrings)
96 {
97 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
98     size_t count = originStrings.size();
99     for (size_t i = 0; i < count; ++i)
100         m_permissionsMap.remove(originStrings[i]);
101 #else
102     UNUSED_PARAM(originStrings);
103 #endif
104 }
105
106 NotificationClient::Permission WebNotificationManager::policyForOrigin(WebCore::SecurityOrigin *origin) const
107 {
108 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
109     if (!origin)
110         return NotificationClient::PermissionNotAllowed;
111
112     ASSERT(!origin->isUnique());
113     HashMap<String, bool>::const_iterator it = m_permissionsMap.find(origin->toRawString());
114     if (it != m_permissionsMap.end())
115         return it->value ? NotificationClient::PermissionAllowed : NotificationClient::PermissionDenied;
116 #else
117     UNUSED_PARAM(origin);
118 #endif
119     
120     return NotificationClient::PermissionNotAllowed;
121 }
122
123 void WebNotificationManager::removeAllPermissionsForTesting()
124 {
125 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
126     m_permissionsMap.clear();
127 #endif
128 }
129
130 uint64_t WebNotificationManager::notificationIDForTesting(Notification* notification)
131 {
132 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
133     if (!notification)
134         return 0;
135     return m_notificationMap.get(notification);
136 #else
137     UNUSED_PARAM(notification);
138     return 0;
139 #endif
140 }
141
142 bool WebNotificationManager::show(Notification* notification, WebPage* page)
143 {
144 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
145     if (!notification || !page->corePage()->settings()->notificationsEnabled())
146         return false;
147     
148     uint64_t notificationID = generateNotificationID();
149     m_notificationMap.set(notification, notificationID);
150     m_notificationIDMap.set(notificationID, notification);
151     
152     NotificationContextMap::iterator it = m_notificationContextMap.add(notification->scriptExecutionContext(), Vector<uint64_t>()).iterator;
153     it->value.append(notificationID);
154
155 #if ENABLE(NOTIFICATIONS)
156     m_process->connection()->send(Messages::WebPageProxy::ShowNotification(notification->title(), notification->body(), notification->iconURL().string(), notification->tag(), notification->lang(), notification->dir(), notification->scriptExecutionContext()->securityOrigin()->toString(), notificationID), page->pageID());
157 #else
158     m_process->connection()->send(Messages::WebPageProxy::ShowNotification(notification->title(), notification->body(), notification->iconURL().string(), notification->replaceId(), notification->lang(), notification->dir(), notification->scriptExecutionContext()->securityOrigin()->toString(), notificationID), page->pageID());
159 #endif
160     return true;
161 #else
162     UNUSED_PARAM(notification);
163     UNUSED_PARAM(page);
164     return false;
165 #endif
166 }
167
168 void WebNotificationManager::cancel(Notification* notification, WebPage* page)
169 {
170 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
171     if (!notification || !page->corePage()->settings()->notificationsEnabled())
172         return;
173     
174     uint64_t notificationID = m_notificationMap.get(notification);
175     if (!notificationID)
176         return;
177     
178     m_process->connection()->send(Messages::WebNotificationManagerProxy::Cancel(notificationID), 0);
179 #else
180     UNUSED_PARAM(notification);
181     UNUSED_PARAM(page);
182 #endif
183 }
184
185 void WebNotificationManager::clearNotifications(WebCore::ScriptExecutionContext* context, WebPage* page)
186 {
187 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
188     NotificationContextMap::iterator it = m_notificationContextMap.find(context);
189     if (it == m_notificationContextMap.end())
190         return;
191     
192     Vector<uint64_t>& notificationIDs = it->value;
193     m_process->connection()->send(Messages::WebNotificationManagerProxy::ClearNotifications(notificationIDs), 0);
194     size_t count = notificationIDs.size();
195     for (size_t i = 0; i < count; ++i) {
196         RefPtr<Notification> notification = m_notificationIDMap.take(notificationIDs[i]);
197         if (!notification)
198             continue;
199         notification->finalize();
200         m_notificationMap.remove(notification);
201     }
202     
203     m_notificationContextMap.remove(it);
204 #else
205     UNUSED_PARAM(context);
206     UNUSED_PARAM(page);
207 #endif
208 }
209
210 void WebNotificationManager::didDestroyNotification(Notification* notification, WebPage* page)
211 {
212 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
213     uint64_t notificationID = m_notificationMap.take(notification);
214     if (!notificationID)
215         return;
216
217     m_notificationIDMap.remove(notificationID);
218     removeNotificationFromContextMap(notificationID, notification);
219     m_process->connection()->send(Messages::WebNotificationManagerProxy::DidDestroyNotification(notificationID), 0);
220 #else
221     UNUSED_PARAM(notification);
222     UNUSED_PARAM(page);
223 #endif
224 }
225
226 void WebNotificationManager::didShowNotification(uint64_t notificationID)
227 {
228 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
229     if (!isNotificationIDValid(notificationID))
230         return;
231     
232     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
233     if (!notification)
234         return;
235
236     notification->dispatchShowEvent();
237 #else
238     UNUSED_PARAM(notificationID);
239 #endif
240 }
241
242 void WebNotificationManager::didClickNotification(uint64_t notificationID)
243 {
244 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
245     if (!isNotificationIDValid(notificationID))
246         return;
247
248     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
249     if (!notification)
250         return;
251
252     // Indicate that this event is being dispatched in reaction to a user's interaction with a platform notification.
253     UserGestureIndicator indicator(DefinitelyProcessingNewUserGesture);
254     notification->dispatchClickEvent();
255 #else
256     UNUSED_PARAM(notificationID);
257 #endif
258 }
259
260 void WebNotificationManager::didCloseNotifications(const Vector<uint64_t>& notificationIDs)
261 {
262 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
263     size_t count = notificationIDs.size();
264     for (size_t i = 0; i < count; ++i) {
265         uint64_t notificationID = notificationIDs[i];
266         if (!isNotificationIDValid(notificationID))
267             continue;
268
269         RefPtr<Notification> notification = m_notificationIDMap.take(notificationID);
270         if (!notification)
271             continue;
272
273         m_notificationMap.remove(notification);
274         removeNotificationFromContextMap(notificationID, notification.get());
275
276         notification->dispatchCloseEvent();
277     }
278 #else
279     UNUSED_PARAM(notificationIDs);
280 #endif
281 }
282
283 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
284 void WebNotificationManager::removeNotificationFromContextMap(uint64_t notificationID, Notification* notification)
285 {
286     // This is a helper function for managing the hash maps.
287     NotificationContextMap::iterator it = m_notificationContextMap.find(notification->scriptExecutionContext());
288     ASSERT(it != m_notificationContextMap.end());
289     size_t index = it->value.find(notificationID);
290     ASSERT(index != notFound);
291     it->value.remove(index);
292     if (it->value.isEmpty())
293         m_notificationContextMap.remove(it);
294 }
295 #endif
296
297 } // namespace WebKit