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/v8/Dictionary.h"
     35 #include "bindings/v8/ScriptWrappable.h"
     36 #include "core/dom/Document.h"
     37 #include "core/frame/UseCounter.h"
     38 #include "core/page/WindowFocusAllowedIndicator.h"
     39 #include "modules/notifications/NotificationClient.h"
     40 #include "modules/notifications/NotificationController.h"
     41 
     42 namespace WebCore {
     43 
     44 Notification* Notification::create(ExecutionContext* context, const String& title, const Dictionary& options)
     45 {
     46     NotificationClient& client = NotificationController::clientFrom(toDocument(context)->frame());
     47     Notification* notification = adoptRefCountedGarbageCollectedWillBeNoop(new Notification(title, context, &client));
     48 
     49     String argument;
     50     if (options.get("body", argument))
     51         notification->setBody(argument);
     52     if (options.get("tag", argument))
     53         notification->setTag(argument);
     54     if (options.get("lang", argument))
     55         notification->setLang(argument);
     56     if (options.get("dir", argument))
     57         notification->setDir(argument);
     58     if (options.get("icon", argument)) {
     59         KURL iconUrl = argument.isEmpty() ? KURL() : context->completeURL(argument);
     60         if (!iconUrl.isEmpty() && iconUrl.isValid())
     61             notification->setIconUrl(iconUrl);
     62     }
     63 
     64     notification->suspendIfNeeded();
     65     return notification;
     66 }
     67 
     68 Notification::Notification(const String& title, ExecutionContext* context, NotificationClient* client)
     69     : ActiveDOMObject(context)
     70     , m_title(title)
     71     , m_dir("auto")
     72     , m_state(Idle)
     73     , m_client(client)
     74     , m_asyncRunner(adoptPtr(new AsyncMethodRunner<Notification>(this, &Notification::show)))
     75 {
     76     ASSERT(m_client);
     77     ScriptWrappable::init(this);
     78 
     79     m_asyncRunner->runAsync();
     80 }
     81 
     82 Notification::~Notification()
     83 {
     84 }
     85 
     86 void Notification::show()
     87 {
     88     ASSERT(m_state == Idle);
     89     if (!toDocument(executionContext())->page())
     90         return;
     91 
     92     if (m_client->checkPermission(executionContext()) != NotificationClient::PermissionAllowed) {
     93         dispatchErrorEvent();
     94         return;
     95     }
     96 
     97     if (m_client->show(this))
     98         m_state = Showing;
     99 }
    100 
    101 void Notification::close()
    102 {
    103     switch (m_state) {
    104     case Idle:
    105         break;
    106     case Showing:
    107         m_client->close(this);
    108         break;
    109     case Closed:
    110         break;
    111     }
    112 }
    113 
    114 void Notification::dispatchShowEvent()
    115 {
    116     dispatchEvent(Event::create(EventTypeNames::show));
    117 }
    118 
    119 void Notification::dispatchClickEvent()
    120 {
    121     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
    122     WindowFocusAllowedIndicator windowFocusAllowed;
    123     dispatchEvent(Event::create(EventTypeNames::click));
    124 }
    125 
    126 void Notification::dispatchErrorEvent()
    127 {
    128     dispatchEvent(Event::create(EventTypeNames::error));
    129 }
    130 
    131 void Notification::dispatchCloseEvent()
    132 {
    133     dispatchEvent(Event::create(EventTypeNames::close));
    134     m_state = Closed;
    135 }
    136 
    137 TextDirection Notification::direction() const
    138 {
    139     // FIXME: Resolve dir()=="auto" against the document.
    140     return dir() == "rtl" ? RTL : LTR;
    141 }
    142 
    143 const String& Notification::permissionString(NotificationClient::Permission permission)
    144 {
    145     DEFINE_STATIC_LOCAL(const String, allowedPermission, ("granted"));
    146     DEFINE_STATIC_LOCAL(const String, deniedPermission, ("denied"));
    147     DEFINE_STATIC_LOCAL(const String, defaultPermission, ("default"));
    148 
    149     switch (permission) {
    150     case NotificationClient::PermissionAllowed:
    151         return allowedPermission;
    152     case NotificationClient::PermissionDenied:
    153         return deniedPermission;
    154     case NotificationClient::PermissionNotAllowed:
    155         return defaultPermission;
    156     }
    157 
    158     ASSERT_NOT_REACHED();
    159     return deniedPermission;
    160 }
    161 
    162 const String& Notification::permission(ExecutionContext* context)
    163 {
    164     ASSERT(toDocument(context)->page());
    165 
    166     UseCounter::count(context, UseCounter::NotificationPermission);
    167     return permissionString(NotificationController::clientFrom(toDocument(context)->frame()).checkPermission(context));
    168 }
    169 
    170 void Notification::requestPermission(ExecutionContext* context, PassOwnPtr<NotificationPermissionCallback> callback)
    171 {
    172     ASSERT(toDocument(context)->page());
    173     NotificationController::clientFrom(toDocument(context)->frame()).requestPermission(context, callback);
    174 }
    175 
    176 bool Notification::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
    177 {
    178     ASSERT(m_state != Closed);
    179 
    180     return EventTarget::dispatchEvent(event);
    181 }
    182 
    183 const AtomicString& Notification::interfaceName() const
    184 {
    185     return EventTargetNames::Notification;
    186 }
    187 
    188 void Notification::stop()
    189 {
    190     if (m_client)
    191         m_client->notificationObjectDestroyed(this);
    192 
    193     if (m_asyncRunner)
    194         m_asyncRunner->stop();
    195 
    196     m_client = 0;
    197     m_state = Closed;
    198 }
    199 
    200 bool Notification::hasPendingActivity() const
    201 {
    202     return m_state == Showing || (m_asyncRunner && m_asyncRunner->isActive());
    203 }
    204 
    205 } // namespace WebCore
    206