• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_SYNC_NOTIFIER_CHROME_NOTIFIER_SERVICE_H_
6 #define CHROME_BROWSER_NOTIFICATIONS_SYNC_NOTIFIER_CHROME_NOTIFIER_SERVICE_H_
7 
8 #include <set>
9 #include <string>
10 
11 #include "base/basictypes.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/threading/thread_checker.h"
16 #include "chrome/browser/notifications/notification.h"
17 #include "chrome/browser/notifications/sync_notifier/synced_notification.h"
18 #include "components/keyed_service/core/keyed_service.h"
19 #include "sync/api/syncable_service.h"
20 #include "ui/message_center/notifier_settings.h"
21 
22 class NotificationUIManager;
23 class Profile;
24 class SyncedNotificationsShim;
25 
26 namespace extensions {
27 struct Event;
28 }
29 
30 namespace user_prefs {
31 class PrefRegistrySyncable;
32 }
33 
34 namespace message_center {
35 struct Notifier;
36 }
37 
38 namespace notifier {
39 class SyncedNotificationAppInfo;
40 class SyncedNotificationAppInfoService;
41 
42 // The name of our first synced notification service.
43 // TODO(petewil): Remove this once we figure out how to do UMA for each sending
44 // service name without knowing the name in advance.
45 extern const char kFirstSyncedNotificationServiceId[];
46 extern const char kServiceEnabledOnce[];
47 extern const char kSyncedNotificationFirstRun[];
48 extern const char kSyncedNotificationsWelcomeOrigin[];
49 
50 enum ChromeNotifierServiceActionType {
51   CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN,
52   CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED,
53   CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED,
54   // NOTE: Add new action types only immediately above this line. Also,
55   // make sure the enum list in tools/histogram/histograms.xml is
56   // updated with any change in here.
57   CHROME_NOTIFIER_SERVICE_ACTION_COUNT
58 };
59 
60 // The ChromeNotifierService holds notifications which represent the state of
61 // delivered notifications for chrome. These are obtained from the sync service
62 // and kept up to date.
63 class ChromeNotifierService : public syncer::SyncableService,
64                               public KeyedService {
65  public:
66   ChromeNotifierService(Profile* profile, NotificationUIManager* manager);
67   virtual ~ChromeNotifierService();
68 
69   // Methods from KeyedService.
70   virtual void Shutdown() OVERRIDE;
71 
72   // Returns the SyncableService for syncer::SYNCED_NOTIFICATIONS and
73   // syncer::SYNCED_NOTIFICATION_APP_INFO
74   SyncedNotificationsShim* GetSyncedNotificationsShim();
75 
76   // syncer::SyncableService implementation.
77   virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
78       syncer::ModelType type,
79       const syncer::SyncDataList& initial_sync_data,
80       scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
81       scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE;
82   virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
83   virtual syncer::SyncDataList GetAllSyncData(
84       syncer::ModelType type) const OVERRIDE;
85   virtual syncer::SyncError ProcessSyncChanges(
86       const tracked_objects::Location& from_here,
87       const syncer::SyncChangeList& change_list) OVERRIDE;
88 
89   // Convert from internal representation to SyncData representation.
90   static syncer::SyncData CreateSyncDataFromNotification(
91       const SyncedNotification& notification);
92 
93   // Convert from SyncData representation to internal representation.
94   scoped_ptr<SyncedNotification> CreateNotificationFromSyncData(
95       const syncer::SyncData& sync_data);
96 
97   // Get a pointer to a notification.  ChromeNotifierService owns this pointer.
98   virtual notifier::SyncedNotification* FindNotificationById(
99       const std::string& notification_id);
100 
101   // Get the list of synced notification services and fill their meta data to
102   // |notifiers|.
103   void GetSyncedNotificationServices(
104       std::vector<message_center::Notifier*>* notifiers);
105 
106   // Called when we dismiss a notification.  This is virtual so that test
107   // subclasses can override it.
108   virtual void MarkNotificationAsRead(const std::string& id);
109 
110   // Called when a notier is enabled or disabled.
111   void OnSyncedNotificationServiceEnabled(
112       const std::string& notifier_id,
113       bool enabled);
114 
115   // When app ids are added or removed, unblock or remove associated messages.
116   void OnAddedAppIds(std::vector<std::string> added_app_ids);
117   void OnRemovedAppIds(std::vector<std::string> removed_app_ids);
118 
119   // Register the preferences we use to save state.
120   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
121 
profile()122   Profile* profile() const { return profile_; }
123 
124   // Find and retun the sending service Id for this notification.
125   std::string GetSendingServiceId(
126       const SyncedNotification* synced_notification);
127 
128   // Functions for test.
129   void AddForTest(scoped_ptr<notifier::SyncedNotification> notification);
130 
131   void SetSyncedNotificationAppInfoServiceForTest(
132       SyncedNotificationAppInfoService* synced_notification_app_info_service);
133 
134   // If we allow the tests to do bitmap fetching, they will attempt to fetch
135   // a URL from the web, which will fail.  We can already test the majority
136   // of what we want without also trying to fetch bitmaps.  Other tests will
137   // cover bitmap fetching.
set_avoid_bitmap_fetching_for_test(bool avoid)138   static void set_avoid_bitmap_fetching_for_test(bool avoid) {
139     avoid_bitmap_fetching_for_test_ = avoid;
140   }
141 
142   // Initialize the preferences we use for the ChromeNotificationService.
143   void InitializePrefs();
144 
145   void ShowWelcomeToastIfNecessary(
146       const SyncedNotification* notification,
147       NotificationUIManager* notification_ui_manager);
148 
149  private:
150   // Helper method for firing JS events triggered by sync.
151   void FireSyncJSEvent(scoped_ptr<extensions::Event> event);
152 
153   // Add a notification to our list.  This takes ownership of the pointer.
154   void Add(scoped_ptr<notifier::SyncedNotification> notification);
155 
156   // Display this notification in the notification center, or remove it.
157   void UpdateInMessageCenter(notifier::SyncedNotification* notification);
158 
159   // Display a notification in the notification center (eventually).
160   void Display(notifier::SyncedNotification* notification);
161 
162   // Remove a notification from our store.
163   void FreeNotificationById(const std::string& notification_id);
164 
165   // When a service it turned on, scan our cache for any notifications
166   // for that service, and display them if they are unread.
167   void DisplayUnreadNotificationsFromSource(const std::string& notifier_id);
168 
169   // When a service it turned off, scan our cache for any notifications
170   // for that service, and remove them from the message center.
171   void RemoveUnreadNotificationsFromSource(const std::string& notifier_id);
172 
173   // When we turn a sending service on or off, collect statistics about
174   // how often users turn it on or off.
175   void CollectPerServiceEnablingStatistics(const std::string& notifier_id,
176                                            bool enabled);
177 
178   // Called when the string list pref has been changed.
179   void OnEnabledSendingServiceListPrefChanged(std::set<std::string>* ids_field);
180 
181   // Called when the string list pref has been changed.
182   void OnInitializedSendingServiceListPrefChanged(
183       std::set<std::string>* ids_field);
184 
185   // Called when our "first run" boolean pref has been changed.
186   void OnSyncedNotificationFirstRunBooleanPrefChanged(bool* new_value);
187 
188   // Convert our internal set of strings to a list value.
189   // The second param is an outparam which the function fills in.
190   void BuildServiceListValueInplace(
191       std::set<std::string> services, base::ListValue* list_value);
192 
193   // Finds an app info by using the AppId
194   notifier::SyncedNotificationAppInfo* FindAppInfoByAppId(
195       const std::string& app_id) const;
196 
197   // Builds a welcome notification for the listed sending service.
198   const Notification CreateWelcomeNotificationForService(
199       SyncedNotificationAppInfo* app_info);
200 
201   // Preferences for storing which SyncedNotificationServices are enabled
202   StringListPrefMember enabled_sending_services_prefs_;
203   StringListPrefMember initialized_sending_services_prefs_;
204 
205   // Preferences to avoid toasting on SyncedNotification first run.
206   BooleanPrefMember synced_notification_first_run_prefs_;
207 
208   // Back pointer to the owning profile.
209   Profile* const profile_;
210   NotificationUIManager* const notification_manager_;
211   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
212   std::set<std::string> enabled_sending_services_;
213   std::set<std::string> initialized_sending_services_;
214   bool synced_notification_first_run_;
215   static bool avoid_bitmap_fetching_for_test_;
216   base::ThreadChecker thread_checker_;
217   // Unowned pointer to the App Info service.  The lifetime is managed by the
218   // profile service, this service depends on the App Info service, so it should
219   // always be in scope whenever our service is active.
220   SyncedNotificationAppInfoService* synced_notification_app_info_service_;
221 
222   // TODO(petewil): Consider whether a map would better suit our data.
223   // If there are many entries, lookup time may trump locality of reference.
224   ScopedVector<SyncedNotification> notification_data_;
225 
226   // Shim connecting the JS private api to sync. // TODO(zea): delete all other
227   // code.
228   scoped_ptr<SyncedNotificationsShim> synced_notifications_shim_;
229 
230   base::WeakPtrFactory<ChromeNotifierService> weak_ptr_factory_;
231 
232   friend class ChromeNotifierServiceTest;
233   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest, ServiceEnabledTest);
234   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest,
235                            AddNewSendingServicesTest);
236   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest,
237                            CheckInitializedServicesTest);
238   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest,
239                            GetEnabledSendingServicesFromPreferencesTest);
240   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest, CheckFindAppInfo);
241   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest, SetAddedAppIdsTest);
242   FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest, SetRemovedAppIdsTest);
243 
244   DISALLOW_COPY_AND_ASSIGN(ChromeNotifierService);
245 };
246 
247 }  // namespace notifier
248 
249 #endif  // CHROME_BROWSER_NOTIFICATIONS_SYNC_NOTIFIER_CHROME_NOTIFIER_SERVICE_H_
250