1 /* 2 * Copyright (C) 2013 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "modules/notifications/Notification.h" 33 34 #include "bindings/core/v8/ScriptWrappable.h" 35 #include "core/dom/Document.h" 36 #include "core/events/Event.h" 37 #include "core/page/WindowFocusAllowedIndicator.h" 38 #include "modules/notifications/NotificationClient.h" 39 #include "modules/notifications/NotificationController.h" 40 #include "modules/notifications/NotificationOptions.h" 41 #include "modules/notifications/NotificationPermissionClient.h" 42 43 namespace blink { 44 45 Notification* Notification::create(ExecutionContext* context, const String& title, const NotificationOptions& options) 46 { 47 NotificationClient& client = NotificationController::clientFrom(context); 48 Notification* notification = adoptRefCountedGarbageCollectedWillBeNoop(new Notification(title, context, &client)); 49 50 notification->setBody(options.body()); 51 notification->setTag(options.tag()); 52 notification->setLang(options.lang()); 53 notification->setDir(options.dir()); 54 if (options.hasIcon()) { 55 KURL iconUrl = options.icon().isEmpty() ? KURL() : context->completeURL(options.icon()); 56 if (!iconUrl.isEmpty() && iconUrl.isValid()) 57 notification->setIconUrl(iconUrl); 58 } 59 60 notification->suspendIfNeeded(); 61 return notification; 62 } 63 64 Notification::Notification(const String& title, ExecutionContext* context, NotificationClient* client) 65 : ActiveDOMObject(context) 66 , m_title(title) 67 , m_dir("auto") 68 , m_state(NotificationStateIdle) 69 , m_client(client) 70 , m_asyncRunner(this, &Notification::show) 71 { 72 ASSERT(m_client); 73 74 m_asyncRunner.runAsync(); 75 } 76 77 Notification::~Notification() 78 { 79 } 80 81 void Notification::show() 82 { 83 ASSERT(m_state == NotificationStateIdle); 84 if (!toDocument(executionContext())->page()) 85 return; 86 87 if (m_client->checkPermission(executionContext()) != NotificationClient::PermissionAllowed) { 88 dispatchErrorEvent(); 89 return; 90 } 91 92 if (m_client->show(this)) 93 m_state = NotificationStateShowing; 94 } 95 96 void Notification::close() 97 { 98 switch (m_state) { 99 case NotificationStateIdle: 100 break; 101 case NotificationStateShowing: 102 m_client->close(this); 103 break; 104 case NotificationStateClosed: 105 break; 106 } 107 } 108 109 void Notification::dispatchShowEvent() 110 { 111 dispatchEvent(Event::create(EventTypeNames::show)); 112 } 113 114 void Notification::dispatchClickEvent() 115 { 116 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 117 WindowFocusAllowedIndicator windowFocusAllowed; 118 dispatchEvent(Event::create(EventTypeNames::click)); 119 } 120 121 void Notification::dispatchErrorEvent() 122 { 123 dispatchEvent(Event::create(EventTypeNames::error)); 124 } 125 126 void Notification::dispatchCloseEvent() 127 { 128 dispatchEvent(Event::create(EventTypeNames::close)); 129 m_state = NotificationStateClosed; 130 } 131 132 TextDirection Notification::direction() const 133 { 134 // FIXME: Resolve dir()=="auto" against the document. 135 return dir() == "rtl" ? RTL : LTR; 136 } 137 138 const String& Notification::permissionString(NotificationClient::Permission permission) 139 { 140 DEFINE_STATIC_LOCAL(const String, allowedPermission, ("granted")); 141 DEFINE_STATIC_LOCAL(const String, deniedPermission, ("denied")); 142 DEFINE_STATIC_LOCAL(const String, defaultPermission, ("default")); 143 144 switch (permission) { 145 case NotificationClient::PermissionAllowed: 146 return allowedPermission; 147 case NotificationClient::PermissionDenied: 148 return deniedPermission; 149 case NotificationClient::PermissionNotAllowed: 150 return defaultPermission; 151 } 152 153 ASSERT_NOT_REACHED(); 154 return deniedPermission; 155 } 156 157 const String& Notification::permission(ExecutionContext* context) 158 { 159 return permissionString(NotificationController::clientFrom(context).checkPermission(context)); 160 } 161 162 void Notification::requestPermission(ExecutionContext* context, NotificationPermissionCallback* callback) 163 { 164 // FIXME: Assert that this code-path will only be reached for Document environments 165 // when Blink supports [Exposed] annotations on class members in IDL definitions. 166 if (NotificationPermissionClient* permissionClient = NotificationPermissionClient::from(context)) { 167 permissionClient->requestPermission(context, callback); 168 return; 169 } 170 } 171 172 bool Notification::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 173 { 174 ASSERT(m_state != NotificationStateClosed); 175 176 return EventTarget::dispatchEvent(event); 177 } 178 179 const AtomicString& Notification::interfaceName() const 180 { 181 return EventTargetNames::Notification; 182 } 183 184 void Notification::stop() 185 { 186 m_state = NotificationStateClosed; 187 188 if (m_client) { 189 m_client->notificationObjectDestroyed(this); 190 m_client = 0; 191 } 192 193 m_asyncRunner.stop(); 194 } 195 196 bool Notification::hasPendingActivity() const 197 { 198 return m_state == NotificationStateShowing || m_asyncRunner.isActive(); 199 } 200 201 } // namespace blink 202