74e35f6b37c0b95f2af669306b3da968f8b8b045
[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 "WebPageProxyMessages.h"
37 #include <WebCore/Document.h>
38 #include <WebCore/Notification.h>
39 #include <WebCore/Page.h>
40 #include <WebCore/ScriptExecutionContext.h>
41 #include <WebCore/SecurityOrigin.h>
42 #include <WebCore/Settings.h>
43 #include <WebCore/UserGestureIndicator.h>
44 #endif
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
51 static uint64_t generateNotificationID()
52 {
53     static uint64_t uniqueNotificationID = 1;
54     return uniqueNotificationID++;
55 }
56 #endif
57
58 const char* WebNotificationManager::supplementName()
59 {
60     return "WebNotificationManager";
61 }
62
63 WebNotificationManager::WebNotificationManager(WebProcess* process)
64     : m_process(process)
65 {
66 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
67     m_process->addMessageReceiver(Messages::WebNotificationManager::messageReceiverName(), *this);
68 #endif
69 }
70
71 WebNotificationManager::~WebNotificationManager()
72 {
73 }
74
75 void WebNotificationManager::initialize(const WebProcessCreationParameters& parameters)
76 {
77 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
78     m_permissionsMap = parameters.notificationPermissions;
79 #else
80     UNUSED_PARAM(parameters);
81 #endif
82 }
83
84 void WebNotificationManager::didUpdateNotificationDecision(const String& originString, bool allowed)
85 {
86 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
87     m_permissionsMap.set(originString, allowed);
88 #else
89     UNUSED_PARAM(originString);
90     UNUSED_PARAM(allowed);
91 #endif
92 }
93
94 void WebNotificationManager::didRemoveNotificationDecisions(const Vector<String>& originStrings)
95 {
96 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
97     size_t count = originStrings.size();
98     for (size_t i = 0; i < count; ++i)
99         m_permissionsMap.remove(originStrings[i]);
100 #else
101     UNUSED_PARAM(originStrings);
102 #endif
103 }
104
105 NotificationClient::Permission WebNotificationManager::policyForOrigin(WebCore::SecurityOrigin *origin) const
106 {
107 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
108     if (!origin)
109         return NotificationClient::PermissionNotAllowed;
110
111     ASSERT(!origin->isUnique());
112     HashMap<String, bool>::const_iterator it = m_permissionsMap.find(origin->toRawString());
113     if (it != m_permissionsMap.end())
114         return it->value ? NotificationClient::PermissionAllowed : NotificationClient::PermissionDenied;
115 #else
116     UNUSED_PARAM(origin);
117 #endif
118     
119     return NotificationClient::PermissionNotAllowed;
120 }
121
122 void WebNotificationManager::removeAllPermissionsForTesting()
123 {
124 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
125     m_permissionsMap.clear();
126 #endif
127 }
128
129 uint64_t WebNotificationManager::notificationIDForTesting(Notification* notification)
130 {
131 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
132     if (!notification)
133         return 0;
134     return m_notificationMap.get(notification);
135 #else
136     UNUSED_PARAM(notification);
137     return 0;
138 #endif
139 }
140
141 bool WebNotificationManager::show(Notification* notification, WebPage* page)
142 {
143 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
144     if (!notification || !page->corePage()->settings().notificationsEnabled())
145         return false;
146     
147     uint64_t notificationID = generateNotificationID();
148     m_notificationMap.set(notification, notificationID);
149     m_notificationIDMap.set(notificationID, notification);
150     
151     NotificationContextMap::iterator it = m_notificationContextMap.add(notification->scriptExecutionContext(), Vector<uint64_t>()).iterator;
152     it->value.append(notificationID);
153
154 #if ENABLE(NOTIFICATIONS)
155     m_process->parentProcessConnection()->send(Messages::WebPageProxy::ShowNotification(notification->title(), notification->body(), notification->iconURL().string(), notification->tag(), notification->lang(), notification->dir(), notification->scriptExecutionContext()->securityOrigin()->toString(), notificationID), page->pageID());
156 #else
157     m_process->parentProcessConnection()->send(Messages::WebPageProxy::ShowNotification(notification->title(), notification->body(), notification->iconURL().string(), notification->replaceId(), notification->lang(), notification->dir(), notification->scriptExecutionContext()->securityOrigin()->toString(), notificationID), page->pageID());
158 #endif
159     return true;
160 #else
161     UNUSED_PARAM(notification);
162     UNUSED_PARAM(page);
163     return false;
164 #endif
165 }
166
167 void WebNotificationManager::cancel(Notification* notification, WebPage* page)
168 {
169 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
170     if (!notification || !page->corePage()->settings().notificationsEnabled())
171         return;
172     
173     uint64_t notificationID = m_notificationMap.get(notification);
174     if (!notificationID)
175         return;
176     
177     m_process->parentProcessConnection()->send(Messages::WebPageProxy::CancelNotification(notificationID), page->pageID());
178 #else
179     UNUSED_PARAM(notification);
180     UNUSED_PARAM(page);
181 #endif
182 }
183
184 void WebNotificationManager::clearNotifications(WebCore::ScriptExecutionContext* context, WebPage* page)
185 {
186 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
187     NotificationContextMap::iterator it = m_notificationContextMap.find(context);
188     if (it == m_notificationContextMap.end())
189         return;
190
191     Vector<uint64_t>& notificationIDs = it->value;
192     m_process->parentProcessConnection()->send(Messages::WebPageProxy::ClearNotifications(notificationIDs), page->pageID());
193     size_t count = notificationIDs.size();
194     for (size_t i = 0; i < count; ++i) {
195         RefPtr<Notification> notification = m_notificationIDMap.take(notificationIDs[i]);
196         if (!notification)
197             continue;
198         notification->finalize();
199         m_notificationMap.remove(notification);
200     }
201     
202     m_notificationContextMap.remove(it);
203 #else
204     UNUSED_PARAM(context);
205     UNUSED_PARAM(page);
206 #endif
207 }
208
209 void WebNotificationManager::didDestroyNotification(Notification* notification, WebPage* page)
210 {
211 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
212     uint64_t notificationID = m_notificationMap.take(notification);
213     if (!notificationID)
214         return;
215
216     m_notificationIDMap.remove(notificationID);
217     removeNotificationFromContextMap(notificationID, notification);
218     m_process->parentProcessConnection()->send(Messages::WebPageProxy::DidDestroyNotification(notificationID), page->pageID());
219 #else
220     UNUSED_PARAM(notification);
221     UNUSED_PARAM(page);
222 #endif
223 }
224
225 void WebNotificationManager::didShowNotification(uint64_t notificationID)
226 {
227 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
228     if (!isNotificationIDValid(notificationID))
229         return;
230     
231     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
232     if (!notification)
233         return;
234
235     notification->dispatchShowEvent();
236 #else
237     UNUSED_PARAM(notificationID);
238 #endif
239 }
240
241 void WebNotificationManager::didClickNotification(uint64_t notificationID)
242 {
243 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
244     if (!isNotificationIDValid(notificationID))
245         return;
246
247     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
248     if (!notification)
249         return;
250
251     // Indicate that this event is being dispatched in reaction to a user's interaction with a platform notification.
252     UserGestureIndicator indicator(ProcessingUserGesture);
253     notification->dispatchClickEvent();
254 #else
255     UNUSED_PARAM(notificationID);
256 #endif
257 }
258
259 void WebNotificationManager::didCloseNotifications(const Vector<uint64_t>& notificationIDs)
260 {
261 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
262     size_t count = notificationIDs.size();
263     for (size_t i = 0; i < count; ++i) {
264         uint64_t notificationID = notificationIDs[i];
265         if (!isNotificationIDValid(notificationID))
266             continue;
267
268         RefPtr<Notification> notification = m_notificationIDMap.take(notificationID);
269         if (!notification)
270             continue;
271
272         m_notificationMap.remove(notification);
273         removeNotificationFromContextMap(notificationID, notification.get());
274
275         notification->dispatchCloseEvent();
276     }
277 #else
278     UNUSED_PARAM(notificationIDs);
279 #endif
280 }
281
282 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
283 void WebNotificationManager::removeNotificationFromContextMap(uint64_t notificationID, Notification* notification)
284 {
285     // This is a helper function for managing the hash maps.
286     NotificationContextMap::iterator it = m_notificationContextMap.find(notification->scriptExecutionContext());
287     ASSERT(it != m_notificationContextMap.end());
288     size_t index = it->value.find(notificationID);
289     ASSERT(index != notFound);
290     it->value.remove(index);
291     if (it->value.isEmpty())
292         m_notificationContextMap.remove(it);
293 }
294 #endif
295
296 } // namespace WebKit