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