Home | History | Annotate | Download | only in notifications
      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