1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/notification_provider.h" 6 7 #include "base/strings/string_util.h" 8 #include "content/common/desktop_notification_messages.h" 9 #include "content/common/view_messages.h" 10 #include "content/renderer/render_view_impl.h" 11 #include "third_party/WebKit/public/platform/WebURL.h" 12 #include "third_party/WebKit/public/web/WebDocument.h" 13 #include "third_party/WebKit/public/web/WebFrame.h" 14 #include "third_party/WebKit/public/web/WebNotificationPermissionCallback.h" 15 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 16 #include "third_party/WebKit/public/web/WebView.h" 17 18 using WebKit::WebDocument; 19 using WebKit::WebNotification; 20 using WebKit::WebNotificationPresenter; 21 using WebKit::WebNotificationPermissionCallback; 22 using WebKit::WebSecurityOrigin; 23 using WebKit::WebString; 24 using WebKit::WebURL; 25 using WebKit::WebUserGestureIndicator; 26 27 namespace content { 28 29 30 NotificationProvider::NotificationProvider(RenderViewImpl* render_view) 31 : RenderViewObserver(render_view) { 32 } 33 34 NotificationProvider::~NotificationProvider() { 35 manager_.DetachAll(); 36 } 37 38 bool NotificationProvider::show(const WebNotification& notification) { 39 int notification_id = manager_.RegisterNotification(notification); 40 if (notification.isHTML()) 41 return ShowHTML(notification, notification_id); 42 else 43 return ShowText(notification, notification_id); 44 } 45 46 void NotificationProvider::cancel(const WebNotification& notification) { 47 int id; 48 bool id_found = manager_.GetId(notification, id); 49 // Won't be found if the notification has already been closed by the user. 50 if (id_found) 51 Send(new DesktopNotificationHostMsg_Cancel(routing_id(), id)); 52 } 53 54 void NotificationProvider::objectDestroyed( 55 const WebNotification& notification) { 56 int id; 57 bool id_found = manager_.GetId(notification, id); 58 // Won't be found if the notification has already been closed by the user. 59 if (id_found) 60 manager_.UnregisterNotification(id); 61 } 62 63 WebNotificationPresenter::Permission NotificationProvider::checkPermission( 64 const WebSecurityOrigin& origin) { 65 int permission; 66 Send(new DesktopNotificationHostMsg_CheckPermission( 67 routing_id(), 68 GURL(origin.toString()), 69 &permission)); 70 return static_cast<WebNotificationPresenter::Permission>(permission); 71 } 72 73 void NotificationProvider::requestPermission( 74 const WebSecurityOrigin& origin, 75 WebNotificationPermissionCallback* callback) { 76 // We only request permission in response to a user gesture. 77 if (!WebUserGestureIndicator::isProcessingUserGesture()) 78 return; 79 80 int id = manager_.RegisterPermissionRequest(callback); 81 82 Send(new DesktopNotificationHostMsg_RequestPermission( 83 routing_id(), GURL(origin.toString()), id)); 84 } 85 86 bool NotificationProvider::OnMessageReceived(const IPC::Message& message) { 87 bool handled = true; 88 IPC_BEGIN_MESSAGE_MAP(NotificationProvider, message) 89 IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostDisplay, OnDisplay); 90 IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostError, OnError); 91 IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostClose, OnClose); 92 IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PostClick, OnClick); 93 IPC_MESSAGE_HANDLER(DesktopNotificationMsg_PermissionRequestDone, 94 OnPermissionRequestComplete); 95 IPC_MESSAGE_UNHANDLED(handled = false) 96 IPC_END_MESSAGE_MAP() 97 98 if (message.type() == ViewMsg_Navigate::ID) 99 OnNavigate(); // Don't want to swallow the message. 100 101 return handled; 102 } 103 104 bool NotificationProvider::ShowHTML(const WebNotification& notification, 105 int id) { 106 DCHECK(notification.isHTML()); 107 ShowDesktopNotificationHostMsgParams params; 108 WebDocument document = render_view()->GetWebView()->mainFrame()->document(); 109 params.origin = GURL(document.securityOrigin().toString()); 110 params.is_html = true; 111 params.contents_url = notification.url(); 112 params.notification_id = id; 113 params.replace_id = notification.replaceId(); 114 return Send(new DesktopNotificationHostMsg_Show(routing_id(), params)); 115 } 116 117 bool NotificationProvider::ShowText(const WebNotification& notification, 118 int id) { 119 DCHECK(!notification.isHTML()); 120 ShowDesktopNotificationHostMsgParams params; 121 params.is_html = false; 122 WebDocument document = render_view()->GetWebView()->mainFrame()->document(); 123 params.origin = GURL(document.securityOrigin().toString()); 124 params.icon_url = notification.iconURL(); 125 params.title = notification.title(); 126 params.body = notification.body(); 127 params.direction = notification.direction(); 128 params.notification_id = id; 129 params.replace_id = notification.replaceId(); 130 return Send(new DesktopNotificationHostMsg_Show(routing_id(), params)); 131 } 132 133 void NotificationProvider::OnDisplay(int id) { 134 WebNotification notification; 135 bool found = manager_.GetNotification(id, ¬ification); 136 // |found| may be false if the WebNotification went out of scope in 137 // the page before it was actually displayed to the user. 138 if (found) 139 notification.dispatchDisplayEvent(); 140 } 141 142 void NotificationProvider::OnError(int id, const WebString& message) { 143 WebNotification notification; 144 bool found = manager_.GetNotification(id, ¬ification); 145 // |found| may be false if the WebNotification went out of scope in 146 // the page before the error occurred. 147 if (found) 148 notification.dispatchErrorEvent(message); 149 } 150 151 void NotificationProvider::OnClose(int id, bool by_user) { 152 WebNotification notification; 153 bool found = manager_.GetNotification(id, ¬ification); 154 // |found| may be false if the WebNotification went out of scope in 155 // the page before the associated toast was closed by the user. 156 if (found) { 157 notification.dispatchCloseEvent(by_user); 158 manager_.UnregisterNotification(id); 159 } 160 } 161 162 void NotificationProvider::OnClick(int id) { 163 WebNotification notification; 164 bool found = manager_.GetNotification(id, ¬ification); 165 // |found| may be false if the WebNotification went out of scope in 166 // the page before the associated toast was clicked on. 167 if (found) 168 notification.dispatchClickEvent(); 169 } 170 171 void NotificationProvider::OnPermissionRequestComplete(int id) { 172 WebNotificationPermissionCallback* callback = manager_.GetCallback(id); 173 DCHECK(callback); 174 callback->permissionRequestComplete(); 175 manager_.OnPermissionRequestComplete(id); 176 } 177 178 void NotificationProvider::OnNavigate() { 179 manager_.Clear(); 180 } 181 182 } // namespace content 183