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 "chrome/browser/notifications/balloon_notification_ui_manager.h"
6
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/prefs/pref_service.h"
10#include "base/stl_util.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/chrome_notification_types.h"
13#include "chrome/browser/fullscreen.h"
14#include "chrome/browser/idle.h"
15#include "chrome/browser/notifications/balloon_collection.h"
16#include "chrome/browser/notifications/notification.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/common/pref_names.h"
19#include "content/public/browser/notification_service.h"
20
21BalloonNotificationUIManager::BalloonNotificationUIManager(
22    PrefService* local_state)
23    : NotificationUIManagerImpl(), NotificationPrefsManager(local_state) {
24  position_pref_.Init(
25      prefs::kDesktopNotificationPosition,
26      local_state,
27      base::Bind(
28          &BalloonNotificationUIManager::OnDesktopNotificationPositionChanged,
29          base::Unretained(this)));
30}
31
32BalloonNotificationUIManager::~BalloonNotificationUIManager() {
33}
34
35void BalloonNotificationUIManager::SetBalloonCollection(
36    BalloonCollection* balloon_collection) {
37  DCHECK(!balloon_collection_.get() ||
38         balloon_collection_->GetActiveBalloons().size() == 0);
39  DCHECK(balloon_collection);
40  balloon_collection_.reset(balloon_collection);
41  balloon_collection_->SetPositionPreference(
42      static_cast<BalloonCollection::PositionPreference>(
43          position_pref_.GetValue()));
44  balloon_collection_->set_space_change_listener(this);
45}
46
47const Notification* BalloonNotificationUIManager::FindById(
48    const std::string& id) const {
49  const Notification* notification = NotificationUIManagerImpl::FindById(id);
50  if (notification)
51    return notification;
52  return balloon_collection_->FindById(id);
53}
54
55bool BalloonNotificationUIManager::CancelById(const std::string& id) {
56  // See if this ID hasn't been shown yet.
57  if (NotificationUIManagerImpl::CancelById(id))
58    return true;
59  // If it has been shown, remove it from the balloon collections.
60  return balloon_collection_->RemoveById(id);
61}
62
63std::set<std::string>
64BalloonNotificationUIManager::GetAllIdsByProfileAndSourceOrigin(
65    Profile* profile,
66    const GURL& source) {
67  std::set<std::string> notification_ids =
68      NotificationUIManagerImpl::GetAllIdsByProfileAndSourceOrigin(profile,
69                                                                   source);
70
71  const BalloonCollection::Balloons& balloons =
72      balloon_collection_->GetActiveBalloons();
73  for (BalloonCollection::Balloons::const_iterator iter = balloons.begin();
74       iter != balloons.end(); ++iter) {
75    if (profile->IsSameProfile((*iter)->profile()) &&
76        source == (*iter)->notification().origin_url()) {
77      notification_ids.insert((*iter)->notification().notification_id());
78    }
79  }
80  return notification_ids;
81}
82
83bool BalloonNotificationUIManager::CancelAllBySourceOrigin(const GURL& source) {
84  // Same pattern as CancelById, but more complicated than the above
85  // because there may be multiple notifications from the same source.
86  bool removed = NotificationUIManagerImpl::CancelAllBySourceOrigin(source);
87  return balloon_collection_->RemoveBySourceOrigin(source) || removed;
88}
89
90bool BalloonNotificationUIManager::CancelAllByProfile(Profile* profile) {
91  // Same pattern as CancelAllBySourceOrigin.
92  bool removed = NotificationUIManagerImpl::CancelAllByProfile(profile);
93  return balloon_collection_->RemoveByProfile(profile) || removed;
94}
95
96void BalloonNotificationUIManager::CancelAll() {
97  NotificationUIManagerImpl::CancelAll();
98  balloon_collection_->RemoveAll();
99}
100
101BalloonCollection* BalloonNotificationUIManager::balloon_collection() {
102  return balloon_collection_.get();
103}
104
105NotificationPrefsManager* BalloonNotificationUIManager::prefs_manager() {
106  return this;
107}
108
109bool BalloonNotificationUIManager::ShowNotification(
110    const Notification& notification,
111    Profile* profile) {
112  if (!balloon_collection_->HasSpace())
113    return false;
114  balloon_collection_->Add(notification, profile);
115  return true;
116}
117
118void BalloonNotificationUIManager::OnBalloonSpaceChanged() {
119  CheckAndShowNotifications();
120}
121
122bool BalloonNotificationUIManager::UpdateNotification(
123    const Notification& notification,
124    Profile* profile) {
125  const GURL& origin = notification.origin_url();
126  const string16& replace_id = notification.replace_id();
127
128  DCHECK(!replace_id.empty());
129
130  const BalloonCollection::Balloons& balloons =
131      balloon_collection_->GetActiveBalloons();
132  for (BalloonCollection::Balloons::const_iterator iter = balloons.begin();
133       iter != balloons.end(); ++iter) {
134    if (profile == (*iter)->profile() &&
135        origin == (*iter)->notification().origin_url() &&
136        replace_id == (*iter)->notification().replace_id()) {
137      (*iter)->Update(notification);
138      return true;
139    }
140  }
141
142  return false;
143}
144
145BalloonCollection::PositionPreference
146BalloonNotificationUIManager::GetPositionPreference() const {
147  LOG(INFO) << "Current position preference: " << position_pref_.GetValue();
148
149  return static_cast<BalloonCollection::PositionPreference>(
150      position_pref_.GetValue());
151}
152
153void BalloonNotificationUIManager::SetPositionPreference(
154    BalloonCollection::PositionPreference preference) {
155  LOG(INFO) << "Setting position preference: " << preference;
156  position_pref_.SetValue(static_cast<int>(preference));
157  balloon_collection_->SetPositionPreference(preference);
158}
159
160void BalloonNotificationUIManager::OnDesktopNotificationPositionChanged() {
161  balloon_collection_->SetPositionPreference(
162      static_cast<BalloonCollection::PositionPreference>(
163          position_pref_.GetValue()));
164}
165
166// static
167BalloonNotificationUIManager*
168    BalloonNotificationUIManager::GetInstanceForTesting() {
169  if (NotificationUIManager::DelegatesToMessageCenter()) {
170    LOG(ERROR) << "Attempt to run a test that requires "
171               << "BalloonNotificationUIManager while delegating to a "
172               << "native MessageCenter. Test will fail. Ask dimich@";
173    return NULL;
174  }
175  return static_cast<BalloonNotificationUIManager*>(
176      g_browser_process->notification_ui_manager());
177}
178