text: // Copyright 2014 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "content/shell/browser/layout_test/layout_test_notification_manager.h"
  
  #include "base/guid.h"
  #include "base/strings/utf_string_conversions.h"
  #include "content/public/browser/browser_thread.h"
  #include "content/public/browser/desktop_notification_delegate.h"
  #include "content/public/browser/notification_event_dispatcher.h"
  #include "content/public/browser/permission_type.h"
  #include "content/public/common/persistent_notification_status.h"
  #include "content/public/common/platform_notification_data.h"
  #include "content/shell/browser/layout_test/layout_test_browser_context.h"
  #include "content/shell/browser/layout_test/layout_test_content_browser_client.h"
  #include "content/shell/browser/layout_test/layout_test_permission_manager.h"
  
  namespace content {
  namespace {
  
  // The Web Notification layout tests don't care about the lifetime of the
  // Service Worker when a notificationclick event has been dispatched.
  void OnEventDispatchComplete(PersistentNotificationStatus status) {}
  
  blink::WebNotificationPermission ToWebNotificationPermission(
      PermissionStatus status) {
    switch (status) {
      case PERMISSION_STATUS_GRANTED:
        return blink::WebNotificationPermissionAllowed;
      case PERMISSION_STATUS_DENIED:
        return blink::WebNotificationPermissionDenied;
      case PERMISSION_STATUS_ASK:
        return blink::WebNotificationPermissionDefault;
    }
  
    NOTREACHED();
    return blink::WebNotificationPermissionLast;
  }
  
  }  // namespace
  
  LayoutTestNotificationManager::LayoutTestNotificationManager()
      : weak_factory_(this) {}
  
  LayoutTestNotificationManager::~LayoutTestNotificationManager() {}
  
  void LayoutTestNotificationManager::DisplayNotification(
      BrowserContext* browser_context,
      const GURL& origin,
      const SkBitmap& icon,
      const PlatformNotificationData& notification_data,
      scoped_ptr<DesktopNotificationDelegate> delegate,
      base::Closure* cancel_callback) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    std::string title = base::UTF16ToUTF8(notification_data.title);
  
    DCHECK(cancel_callback);
    *cancel_callback = base::Bind(&LayoutTestNotificationManager::Close,
                                  weak_factory_.GetWeakPtr(),
                                  title);
  
    ReplaceNotificationIfNeeded(notification_data);
  
    page_notifications_[title] = delegate.release();
    page_notifications_[title]->NotificationDisplayed();
  }
  
  void LayoutTestNotificationManager::DisplayPersistentNotification(
      BrowserContext* browser_context,
      int64_t persistent_notification_id,
      const GURL& origin,
      const SkBitmap& icon,
      const PlatformNotificationData& notification_data) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    std::string title = base::UTF16ToUTF8(notification_data.title);
  
    ReplaceNotificationIfNeeded(notification_data);
  
    PersistentNotification notification;
    notification.browser_context = browser_context;
    notification.origin = origin;
    notification.persistent_id = persistent_notification_id;
  
    persistent_notifications_[title] = notification;
  }
  
  void LayoutTestNotificationManager::ClosePersistentNotification(
      BrowserContext* browser_context,
      int64_t persistent_notification_id) {
    for (const auto& iter : persistent_notifications_) {
      if (iter.second.persistent_id != persistent_notification_id)
        continue;
  
      persistent_notifications_.erase(iter.first);
      return;
    }
  }
  
  bool LayoutTestNotificationManager::GetDisplayedPersistentNotifications(
      BrowserContext* browser_context,
      std::set<std::string>* displayed_notifications) {
    DCHECK(displayed_notifications);
  
    // Notifications will never outlive the lifetime of running layout tests.
    return false;
  }
  
  void LayoutTestNotificationManager::SimulateClick(const std::string& title,
                                                    int action_index) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
  
    // First check for page-notifications with the given title.
    const auto& page_iterator = page_notifications_.find(title);
    if (page_iterator != page_notifications_.end()) {
      DCHECK_EQ(action_index, -1) << "Action buttons are only supported for "
                                     "persistent notifications";
      page_iterator->second->NotificationClick();
      return;
    }
  
    // Then check for persistent notifications with the given title.
    const auto& persistent_iterator = persistent_notifications_.find(title);
    if (persistent_iterator == persistent_notifications_.end())
      return;
  
    const PersistentNotification& notification = persistent_iterator->second;
    content::NotificationEventDispatcher::GetInstance()
        ->DispatchNotificationClickEvent(
            notification.browser_context,
            notification.persistent_id,
            notification.origin,
            action_index,
            base::Bind(&OnEventDispatchComplete));
  }
  
  blink::WebNotificationPermission
  LayoutTestNotificationManager::CheckPermissionOnUIThread(
      BrowserContext* browser_context,
      const GURL& origin,
      int render_process_id) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    return CheckPermission(origin);
  }
  
  blink::WebNotificationPermission
  LayoutTestNotificationManager::CheckPermissionOnIOThread(
      ResourceContext* resource_context,
      const GURL& origin,
      int render_process_id) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    return CheckPermission(origin);
  }
  
  void LayoutTestNotificationManager::Close(const std::string& title) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    auto iterator = page_notifications_.find(title);
    if (iterator == page_notifications_.end())
      return;
  
    iterator->second->NotificationClosed();
  }
  
  void LayoutTestNotificationManager::ReplaceNotificationIfNeeded(
      const PlatformNotificationData& notification_data) {
    if (!notification_data.tag.length())
      return;
  
    std::string tag = notification_data.tag;
    const auto& replace_iter = replacements_.find(tag);
    if (replace_iter != replacements_.end()) {
      const std::string& previous_title = replace_iter->second;
  
      const auto& page_notification_iter =
          page_notifications_.find(previous_title);
      if (page_notification_iter != page_notifications_.end()) {
        DesktopNotificationDelegate* previous_delegate =
            page_notification_iter->second;
  
        previous_delegate->NotificationClosed();
  
        page_notifications_.erase(page_notification_iter);
        delete previous_delegate;
      }
  
      const auto& persistent_notification_iter =
          persistent_notifications_.find(previous_title);
      if (persistent_notification_iter != persistent_notifications_.end())
        persistent_notifications_.erase(persistent_notification_iter);
    }
  
    replacements_[tag] = base::UTF16ToUTF8(notification_data.title);
  }
  
  blink::WebNotificationPermission
  LayoutTestNotificationManager::CheckPermission(const GURL& origin) {
    return ToWebNotificationPermission(LayoutTestContentBrowserClient::Get()
        ->GetLayoutTestBrowserContext()
        ->GetLayoutTestPermissionManager()
        ->GetPermissionStatus(PermissionType::NOTIFICATIONS,
                              origin,
                              origin));
  }
  
  }  // namespace content
  