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#ifndef CHROME_BROWSER_NOTIFICATIONS_MESSAGE_CENTER_NOTIFICATION_MANAGER_H_
6#define CHROME_BROWSER_NOTIFICATIONS_MESSAGE_CENTER_NOTIFICATION_MANAGER_H_
7
8#include <map>
9#include <string>
10
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/scoped_vector.h"
13#include "base/memory/weak_ptr.h"
14#include "base/prefs/pref_member.h"
15#include "base/time/time.h"
16#include "base/timer/timer.h"
17#include "chrome/browser/notifications/google_now_notification_stats_collector.h"
18#include "chrome/browser/notifications/message_center_stats_collector.h"
19#include "chrome/browser/notifications/notification.h"
20#include "chrome/browser/notifications/notification_system_observer.h"
21#include "chrome/browser/notifications/notification_ui_manager.h"
22#include "ui/message_center/message_center.h"
23#include "ui/message_center/message_center_observer.h"
24#include "ui/message_center/message_center_tray_delegate.h"
25#include "ui/message_center/message_center_types.h"
26
27class MessageCenterSettingsController;
28class Notification;
29class PrefRegistrySimple;
30class PrefService;
31class Profile;
32
33namespace message_center {
34class NotificationBlocker;
35FORWARD_DECLARE_TEST(WebNotificationTrayTest, ManuallyCloseMessageCenter);
36}
37
38// This class extends NotificationUIManagerImpl and delegates actual display
39// of notifications to MessageCenter, doing necessary conversions.
40class MessageCenterNotificationManager
41    : public NotificationUIManager,
42      public message_center::MessageCenterObserver {
43 public:
44  MessageCenterNotificationManager(
45      message_center::MessageCenter* message_center,
46      PrefService* local_state,
47      scoped_ptr<message_center::NotifierSettingsProvider> settings_provider);
48  virtual ~MessageCenterNotificationManager();
49
50  // Registers preferences.
51  static void RegisterPrefs(PrefRegistrySimple* registry);
52
53  // NotificationUIManager
54  virtual void Add(const Notification& notification,
55                   Profile* profile) OVERRIDE;
56  virtual bool Update(const Notification& notification,
57                      Profile* profile) OVERRIDE;
58  virtual const Notification* FindById(
59      const std::string& notification_id) const OVERRIDE;
60  virtual bool CancelById(const std::string& notification_id) OVERRIDE;
61  virtual std::set<std::string> GetAllIdsByProfileAndSourceOrigin(
62      Profile* profile,
63      const GURL& source) OVERRIDE;
64  virtual bool CancelAllBySourceOrigin(const GURL& source_origin) OVERRIDE;
65  virtual bool CancelAllByProfile(Profile* profile) OVERRIDE;
66  virtual void CancelAll() OVERRIDE;
67
68  // MessageCenterObserver
69  virtual void OnNotificationRemoved(const std::string& notification_id,
70                                     bool by_user) OVERRIDE;
71  virtual void OnCenterVisibilityChanged(message_center::Visibility) OVERRIDE;
72  virtual void OnNotificationUpdated(const std::string& notification_id)
73      OVERRIDE;
74
75  void EnsureMessageCenterClosed();
76
77#if defined(OS_WIN)
78  // Called when the pref changes for the first run balloon. The first run
79  // balloon is only displayed on Windows, since the visibility of the tray
80  // icon is limited.
81  void DisplayFirstRunBalloon();
82
83  void SetFirstRunTimeoutForTest(base::TimeDelta timeout);
84  bool FirstRunTimerIsActive() const;
85#endif
86
87  // Takes ownership of |delegate|.
88  void SetMessageCenterTrayDelegateForTest(
89      message_center::MessageCenterTrayDelegate* delegate);
90
91 private:
92  FRIEND_TEST_ALL_PREFIXES(message_center::WebNotificationTrayTest,
93                           ManuallyCloseMessageCenter);
94  class ImageDownloadsObserver {
95   public:
96    virtual void OnDownloadsCompleted() = 0;
97  };
98
99  typedef base::Callback<void(const gfx::Image&)> SetImageCallback;
100  class ImageDownloads
101      : public base::SupportsWeakPtr<ImageDownloads> {
102   public:
103    ImageDownloads(
104        message_center::MessageCenter* message_center,
105        ImageDownloadsObserver* observer);
106    virtual ~ImageDownloads();
107
108    void StartDownloads(const Notification& notification);
109    void StartDownloadWithImage(const Notification& notification,
110                                const gfx::Image* image,
111                                const GURL& url,
112                                const SetImageCallback& callback);
113    void StartDownloadByKey(const Notification& notification,
114                            const char* key,
115                            int size,
116                            const SetImageCallback& callback);
117
118    // FaviconHelper callback.
119    void DownloadComplete(const SetImageCallback& callback,
120                          int download_id,
121                          int http_status_code,
122                          const GURL& image_url,
123                          const std::vector<SkBitmap>& bitmaps,
124                          const std::vector<gfx::Size>& original_bitmap_sizes);
125   private:
126    // Used to keep track of the number of pending downloads.  Once this
127    // reaches zero, we can tell the delegate that we don't need the
128    // RenderViewHost anymore.
129    void AddPendingDownload();
130    void PendingDownloadCompleted();
131
132    // Weak reference to global message center.
133    message_center::MessageCenter* message_center_;
134
135    // Count of downloads that remain.
136    size_t pending_downloads_;
137
138    // Weak.
139    ImageDownloadsObserver* observer_;
140
141    DISALLOW_COPY_AND_ASSIGN(ImageDownloads);
142  };
143
144  // This class keeps a set of original Notification objects and corresponding
145  // Profiles, so when MessageCenter calls back with a notification_id, this
146  // class has necessary mapping to other source info - for example, it calls
147  // NotificationDelegate supplied by client when someone clicks on a
148  // Notification in MessageCenter. Likewise, if a Profile or Extension is
149  // being removed, the  map makes it possible to revoke the notifications from
150  // MessageCenter.   To keep that set, we use the private ProfileNotification
151  // class that stores  a superset of all information about a notification.
152
153  // TODO(dimich): Consider merging all 4 types (Notification,
154  // QueuedNotification, ProfileNotification and NotificationList::Notification)
155  // into a single class.
156  class ProfileNotification : public ImageDownloadsObserver {
157   public:
158    ProfileNotification(Profile* profile,
159                        const Notification& notification,
160                        message_center::MessageCenter* message_center);
161    virtual ~ProfileNotification();
162
163    void StartDownloads();
164
165    // Overridden from ImageDownloadsObserver.
166    virtual void OnDownloadsCompleted() OVERRIDE;
167
168    Profile* profile() const { return profile_; }
169    const Notification& notification() const { return notification_; }
170
171    // Route a new notification to an app/extension.
172    void AddToAlternateProvider(const std::string extension_id);
173
174   private:
175    // Weak, guaranteed not to be used after profile removal by parent class.
176    Profile* profile_;
177    Notification notification_;
178    // Track the downloads for this notification so the notification can be
179    // updated properly.
180    scoped_ptr<ImageDownloads> downloads_;
181  };
182
183  scoped_ptr<message_center::MessageCenterTrayDelegate> tray_;
184  message_center::MessageCenter* message_center_;  // Weak, global.
185
186  // Use a map by notification_id since this mapping is the most often used.
187  typedef std::map<std::string, ProfileNotification*> NotificationMap;
188  NotificationMap profile_notifications_;
189
190  // Helpers that add/remove the notification from local map.
191  // The local map takes ownership of profile_notification object.
192  void AddProfileNotification(ProfileNotification* profile_notification);
193  void RemoveProfileNotification(ProfileNotification* profile_notification);
194
195  // Returns the ProfileNotification for the |id|, or NULL if no such
196  // notification is found.
197  ProfileNotification* FindProfileNotification(const std::string& id) const;
198
199  // Get the extension ID of the extension that the user chose to take over
200  // Chorme Notification Center.
201  std::string GetExtensionTakingOverNotifications(Profile* profile);
202
203#if defined(OS_WIN)
204  // This function is run on update to ensure that the notification balloon is
205  // shown only when there are no popups present.
206  void CheckFirstRunTimer();
207
208  // |first_run_pref_| is used to keep track of whether we've ever shown the
209  // first run balloon before, even across restarts.
210  BooleanPrefMember first_run_pref_;
211
212  // The timer after which we will show the first run balloon.  This timer is
213  // restarted every time the message center is closed and every time the last
214  // popup disappears from the screen.
215  base::OneShotTimer<MessageCenterNotificationManager> first_run_balloon_timer_;
216
217  // The first-run balloon will be shown |first_run_idle_timeout_| after all
218  // popups go away and the user has notifications in the message center.
219  base::TimeDelta first_run_idle_timeout_;
220
221  // Provides weak pointers for the purpose of the first run timer.
222  base::WeakPtrFactory<MessageCenterNotificationManager> weak_factory_;
223#endif
224
225  scoped_ptr<message_center::NotifierSettingsProvider> settings_provider_;
226
227  // To own the blockers.
228  ScopedVector<message_center::NotificationBlocker> blockers_;
229
230  NotificationSystemObserver system_observer_;
231
232  // Keeps track of all notification statistics for UMA purposes.
233  MessageCenterStatsCollector stats_collector_;
234
235  // Keeps track of notifications specific to Google Now for UMA purposes.
236  GoogleNowNotificationStatsCollector google_now_stats_collector_;
237
238  DISALLOW_COPY_AND_ASSIGN(MessageCenterNotificationManager);
239};
240
241#endif  // CHROME_BROWSER_NOTIFICATIONS_MESSAGE_CENTER_NOTIFICATION_MANAGER_H_
242