Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / notifications / sync_notifier / chrome_notifier_service.cc
blobc976190f63d790c24634a68cb00116c93b8fb5c0
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.
5 // The ChromeNotifierService works together with sync to maintain the state of
6 // user notifications, which can then be presented in the notification center,
7 // via the Notification UI Manager.
9 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
11 #include <string>
12 #include <vector>
14 #include "base/command_line.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/values.h"
18 #include "chrome/browser/notifications/desktop_notification_service.h"
19 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
20 #include "chrome/browser/notifications/notification.h"
21 #include "chrome/browser/notifications/notification_ui_manager.h"
22 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/pref_names.h"
25 #include "components/user_prefs/pref_registry_syncable.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/user_metrics.h"
28 #include "grit/generated_resources.h"
29 #include "grit/theme_resources.h"
30 #include "sync/api/sync_change.h"
31 #include "sync/api/sync_change_processor.h"
32 #include "sync/api/sync_error_factory.h"
33 #include "sync/protocol/sync.pb.h"
34 #include "sync/protocol/synced_notification_specifics.pb.h"
35 #include "third_party/WebKit/public/web/WebTextDirection.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/message_center/notifier_settings.h"
39 #include "url/gurl.h"
41 using base::UserMetricsAction;
43 namespace notifier {
45 const char kFirstSyncedNotificationServiceId[] = "Google+";
47 bool ChromeNotifierService::avoid_bitmap_fetching_for_test_ = false;
49 ChromeNotifierService::ChromeNotifierService(Profile* profile,
50 NotificationUIManager* manager)
51 : profile_(profile), notification_manager_(manager),
52 synced_notification_first_run_(false) {
53 InitializePrefs();
54 AddNewSendingServices();
56 ChromeNotifierService::~ChromeNotifierService() {}
58 // Methods from BrowserContextKeyedService.
59 void ChromeNotifierService::Shutdown() {}
61 // syncer::SyncableService implementation.
63 // This is called at startup to sync with the server.
64 // This code is not thread safe.
65 syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
66 syncer::ModelType type,
67 const syncer::SyncDataList& initial_sync_data,
68 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
69 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
70 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
71 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
72 syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS);
73 // A list of local changes to send up to the sync server.
74 syncer::SyncChangeList new_changes;
75 sync_processor_ = sync_processor.Pass();
77 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
78 it != initial_sync_data.end(); ++it) {
79 const syncer::SyncData& sync_data = *it;
80 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
82 // Build a local notification object from the sync data.
83 scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData(
84 sync_data));
85 if (!incoming) {
86 // TODO(petewil): Turn this into a NOTREACHED() call once we fix the
87 // underlying problem causing bad data.
88 LOG(WARNING) << "Badly formed sync data in incoming notification";
89 continue;
92 // Process each incoming remote notification.
93 const std::string& key = incoming->GetKey();
94 DCHECK_GT(key.length(), 0U);
95 SyncedNotification* found = FindNotificationById(key);
97 if (NULL == found) {
98 // If there are no conflicts, copy in the data from remote.
99 Add(incoming.Pass());
100 } else {
101 // If the incoming (remote) and stored (local) notifications match
102 // in all fields, we don't need to do anything here.
103 if (incoming->EqualsIgnoringReadState(*found)) {
105 if (incoming->GetReadState() == found->GetReadState()) {
106 // Notification matches on the client and the server, nothing to do.
107 continue;
108 } else {
109 // If the read state is different, read wins for both places.
110 if (incoming->GetReadState() == SyncedNotification::kDismissed) {
111 // If it is marked as read on the server, but not the client.
112 found->NotificationHasBeenDismissed();
113 // Tell the Notification UI Manager to remove it.
114 notification_manager_->CancelById(found->GetKey());
115 } else if (incoming->GetReadState() == SyncedNotification::kRead) {
116 // If it is marked as read on the server, but not the client.
117 found->NotificationHasBeenRead();
118 // Tell the Notification UI Manager to remove it.
119 notification_manager_->CancelById(found->GetKey());
120 } else {
121 // If it is marked as read on the client, but not the server.
122 syncer::SyncData sync_data = CreateSyncDataFromNotification(*found);
123 new_changes.push_back(
124 syncer::SyncChange(FROM_HERE,
125 syncer::SyncChange::ACTION_UPDATE,
126 sync_data));
128 // If local state changed, notify Notification UI Manager.
130 // For any other conflict besides read state, treat it as an update.
131 } else {
132 // If different, just replace the local with the remote.
133 // TODO(petewil): Someday we may allow changes from the client to
134 // flow upwards, when we do, we will need better merge resolution.
135 found->Update(sync_data);
137 // Tell the notification manager to update the notification.
138 UpdateInMessageCenter(found);
143 // Send up the changes that were made locally.
144 if (new_changes.size() > 0) {
145 merge_result.set_error(sync_processor_->ProcessSyncChanges(
146 FROM_HERE, new_changes));
149 // Once we complete our first sync, we mark "first run" as false,
150 // subsequent runs of Synced Notifications will get normal treatment.
151 if (synced_notification_first_run_) {
152 synced_notification_first_run_ = false;
153 profile_->GetPrefs()->SetBoolean(prefs::kSyncedNotificationFirstRun, false);
156 return merge_result;
159 void ChromeNotifierService::StopSyncing(syncer::ModelType type) {
160 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
161 // Since this data type is not user-unselectable, we chose not to implement
162 // the stop syncing method, and instead do nothing here.
165 syncer::SyncDataList ChromeNotifierService::GetAllSyncData(
166 syncer::ModelType type) const {
167 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
168 syncer::SyncDataList sync_data;
170 // Copy our native format data into a SyncDataList format.
171 ScopedVector<SyncedNotification>::const_iterator it =
172 notification_data_.begin();
173 for (; it != notification_data_.end(); ++it) {
174 sync_data.push_back(CreateSyncDataFromNotification(**it));
177 return sync_data;
180 // This method is called when there is an incoming sync change from the server.
181 syncer::SyncError ChromeNotifierService::ProcessSyncChanges(
182 const tracked_objects::Location& from_here,
183 const syncer::SyncChangeList& change_list) {
184 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
185 syncer::SyncError error;
187 for (syncer::SyncChangeList::const_iterator it = change_list.begin();
188 it != change_list.end(); ++it) {
189 syncer::SyncData sync_data = it->sync_data();
190 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
191 syncer::SyncChange::SyncChangeType change_type = it->change_type();
193 scoped_ptr<SyncedNotification> new_notification(
194 CreateNotificationFromSyncData(sync_data));
195 if (!new_notification.get()) {
196 NOTREACHED() << "Failed to read notification.";
197 continue;
200 const std::string& key = new_notification->GetKey();
201 DCHECK_GT(key.length(), 0U);
202 SyncedNotification* found = FindNotificationById(key);
204 switch (change_type) {
205 case syncer::SyncChange::ACTION_ADD:
206 // Intentional fall through, cases are identical.
207 case syncer::SyncChange::ACTION_UPDATE:
208 if (found == NULL) {
209 Add(new_notification.Pass());
210 break;
212 // Update it in our store.
213 found->Update(sync_data);
214 // Tell the notification manager to update the notification.
215 UpdateInMessageCenter(found);
216 break;
218 case syncer::SyncChange::ACTION_DELETE:
219 if (found == NULL) {
220 break;
222 // Remove it from our store.
223 FreeNotificationById(key);
224 // Remove it from the message center.
225 UpdateInMessageCenter(new_notification.get());
226 // TODO(petewil): Do I need to remember that it was deleted in case the
227 // add arrives after the delete? If so, how long do I need to remember?
228 break;
230 default:
231 NOTREACHED();
232 break;
236 return error;
239 // Support functions for data type conversion.
241 // Static method. Get to the sync data in our internal format.
242 syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification(
243 const SyncedNotification& notification) {
244 // Construct the sync_data using the specifics from the notification.
245 return syncer::SyncData::CreateLocalData(
246 notification.GetKey(), notification.GetKey(),
247 notification.GetEntitySpecifics());
250 // Static Method. Convert from SyncData to our internal format.
251 scoped_ptr<SyncedNotification>
252 ChromeNotifierService::CreateNotificationFromSyncData(
253 const syncer::SyncData& sync_data) {
254 // Get a pointer to our data within the sync_data object.
255 sync_pb::SyncedNotificationSpecifics specifics =
256 sync_data.GetSpecifics().synced_notification();
258 // Check for mandatory fields in the sync_data object.
259 if (!specifics.has_coalesced_notification() ||
260 !specifics.coalesced_notification().has_key() ||
261 !specifics.coalesced_notification().has_read_state()) {
262 DVLOG(1) << "Synced Notification missing mandatory fields "
263 << "has coalesced notification? "
264 << specifics.has_coalesced_notification()
265 << " has key? " << specifics.coalesced_notification().has_key()
266 << " has read state? "
267 << specifics.coalesced_notification().has_read_state();
268 return scoped_ptr<SyncedNotification>();
271 bool is_well_formed_unread_notification =
272 (static_cast<SyncedNotification::ReadState>(
273 specifics.coalesced_notification().read_state()) ==
274 SyncedNotification::kUnread &&
275 specifics.coalesced_notification().has_render_info());
276 bool is_well_formed_read_notification =
277 (static_cast<SyncedNotification::ReadState>(
278 specifics.coalesced_notification().read_state()) ==
279 SyncedNotification::kRead);
280 bool is_well_formed_dismissed_notification =
281 (static_cast<SyncedNotification::ReadState>(
282 specifics.coalesced_notification().read_state()) ==
283 SyncedNotification::kDismissed);
285 // If the notification is poorly formed, return a null pointer.
286 if (!is_well_formed_unread_notification &&
287 !is_well_formed_read_notification &&
288 !is_well_formed_dismissed_notification) {
289 DVLOG(1) << "Synced Notification is not well formed."
290 << " unread well formed? "
291 << is_well_formed_unread_notification
292 << " dismissed well formed? "
293 << is_well_formed_dismissed_notification
294 << " read well formed? "
295 << is_well_formed_read_notification;
296 return scoped_ptr<SyncedNotification>();
299 // Create a new notification object based on the supplied sync_data.
300 scoped_ptr<SyncedNotification> notification(
301 new SyncedNotification(sync_data));
303 return notification.Pass();
306 // This returns a pointer into a vector that we own. Caller must not free it.
307 // Returns NULL if no match is found.
308 SyncedNotification* ChromeNotifierService::FindNotificationById(
309 const std::string& notification_id) {
310 // TODO(petewil): We can make a performance trade off here.
311 // While the vector has good locality of reference, a map has faster lookup.
312 // Based on how big we expect this to get, maybe change this to a map.
313 ScopedVector<SyncedNotification>::const_iterator it =
314 notification_data_.begin();
315 for (; it != notification_data_.end(); ++it) {
316 SyncedNotification* notification = *it;
317 if (notification_id == notification->GetKey())
318 return *it;
321 return NULL;
324 void ChromeNotifierService::FreeNotificationById(
325 const std::string& notification_id) {
326 ScopedVector<SyncedNotification>::iterator it = notification_data_.begin();
327 for (; it != notification_data_.end(); ++it) {
328 SyncedNotification* notification = *it;
329 if (notification_id == notification->GetKey()) {
330 notification_data_.erase(it);
331 return;
336 void ChromeNotifierService::GetSyncedNotificationServices(
337 std::vector<message_center::Notifier*>* notifiers) {
338 // TODO(mukai|petewil): Check the profile's eligibility before adding the
339 // sample app.
341 // TODO(petewil): Really obtain the list of synced notification sending
342 // services from the server and create the list of ids here. Until then, we
343 // are hardcoding the service names. Once that is done, remove this
344 // hardcoding.
345 // crbug.com/248337
346 DesktopNotificationService* desktop_notification_service =
347 DesktopNotificationServiceFactory::GetForProfile(profile_);
348 message_center::NotifierId notifier_id(
349 message_center::NotifierId::SYNCED_NOTIFICATION_SERVICE,
350 kFirstSyncedNotificationServiceId);
351 message_center::Notifier* notifier_service = new message_center::Notifier(
352 notifier_id,
353 l10n_util::GetStringUTF16(
354 IDS_FIRST_SYNCED_NOTIFICATION_SERVICE_NAME),
355 desktop_notification_service->IsNotifierEnabled(notifier_id));
357 // Add icons for our sending services.
358 // TODO(petewil): Replace this temporary hardcoding with a new sync datatype
359 // to dynamically get the name and icon for each synced notification sending
360 // service. Until then, we use hardcoded service icons for all services.
361 // crbug.com/248337
362 notifier_service->icon = ui::ResourceBundle::GetSharedInstance().
363 GetImageNamed(IDR_TEMPORARY_GOOGLE_PLUS_ICON);
365 // Enable or disable the sending service per saved settings.
366 std::set<std::string>::iterator iter;
368 iter = find(enabled_sending_services_.begin(),
369 enabled_sending_services_.end(),
370 notifier_id.id);
371 if (iter != enabled_sending_services_.end())
372 notifier_service->enabled = true;
373 else
374 notifier_service->enabled = false;
376 notifiers->push_back(notifier_service);
379 void ChromeNotifierService::MarkNotificationAsRead(
380 const std::string& key) {
381 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
382 SyncedNotification* notification = FindNotificationById(key);
383 CHECK(notification != NULL);
385 notification->NotificationHasBeenRead();
386 syncer::SyncChangeList new_changes;
388 syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
389 new_changes.push_back(
390 syncer::SyncChange(FROM_HERE,
391 syncer::SyncChange::ACTION_UPDATE,
392 sync_data));
394 // Send up the changes that were made locally.
395 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
398 // Add a new notification to our data structure. This takes ownership
399 // of the passed in pointer.
400 void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
401 SyncedNotification* notification_copy = notification.get();
402 // Take ownership of the object and put it into our local storage.
403 notification_data_.push_back(notification.release());
405 // If the user is not interested in this type of notification, ignore it.
406 std::set<std::string>::iterator iter =
407 find(enabled_sending_services_.begin(),
408 enabled_sending_services_.end(),
409 notification_copy->GetSendingServiceId());
410 if (iter == enabled_sending_services_.end()) {
411 return;
414 UpdateInMessageCenter(notification_copy);
417 void ChromeNotifierService::AddForTest(
418 scoped_ptr<notifier::SyncedNotification> notification) {
419 notification_data_.push_back(notification.release());
422 void ChromeNotifierService::UpdateInMessageCenter(
423 SyncedNotification* notification) {
424 // If the feature is disabled, exit now.
425 if (!notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
426 CommandLine::ForCurrentProcess()))
427 return;
429 notification->LogNotification();
431 if (notification->GetReadState() == SyncedNotification::kUnread) {
432 // If the message is unread, update it.
433 Display(notification);
434 } else {
435 // If the message is read or deleted, dismiss it from the center.
436 // We intentionally ignore errors if it is not in the center.
437 notification_manager_->CancelById(notification->GetKey());
441 void ChromeNotifierService::Display(SyncedNotification* notification) {
442 // Set up to fetch the bitmaps.
443 notification->QueueBitmapFetchJobs(notification_manager_,
444 this,
445 profile_);
447 // Our tests cannot use the network for reliability reasons.
448 if (avoid_bitmap_fetching_for_test_) {
449 return;
452 // If this is the first run for the feature, don't surprise the user.
453 // Instead, place all backlogged notifications into the notification
454 // center.
455 if (synced_notification_first_run_) {
456 // Setting the toast state to false will prevent toasting the notification.
457 notification->SetToastState(false);
460 // Start the bitmap fetching, Show() will be called when the last bitmap
461 // either arrives or times out.
462 notification->StartBitmapFetch();
465 void ChromeNotifierService::OnSyncedNotificationServiceEnabled(
466 const std::string& notifier_id, bool enabled) {
467 std::set<std::string>::iterator iter;
469 // Make a copy of the notifier_id, which might not have lifetime long enough
470 // for this function to finish all of its work.
471 std::string notifier_id_copy(notifier_id);
473 iter = find(enabled_sending_services_.begin(),
474 enabled_sending_services_.end(),
475 notifier_id_copy);
477 base::ListValue synced_notification_services;
479 // Add the notifier_id if it is enabled and not already there.
480 if (iter == enabled_sending_services_.end() && enabled) {
481 enabled_sending_services_.insert(notifier_id_copy);
482 // Check now for any outstanding notifications.
483 DisplayUnreadNotificationsFromSource(notifier_id);
484 BuildServiceListValueInplace(enabled_sending_services_,
485 &synced_notification_services);
486 // Add this preference to the enabled list.
487 profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
488 synced_notification_services);
489 // Remove the notifier_id if it is disabled and present.
490 } else if (iter != enabled_sending_services_.end() && !enabled) {
491 enabled_sending_services_.erase(iter);
492 BuildServiceListValueInplace(enabled_sending_services_,
493 &synced_notification_services);
494 // Remove this peference from the enabled list.
495 profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
496 synced_notification_services);
497 RemoveUnreadNotificationsFromSource(notifier_id_copy);
500 // Collect UMA statistics when a service is enabled or disabled.
501 if (enabled) {
502 content::RecordAction(
503 UserMetricsAction("SyncedNotifications.SendingServiceEnabled"));
504 } else {
505 content::RecordAction(
506 UserMetricsAction("SyncedNotifications.SendingServiceDisabled"));
509 // Collect individual service enabling/disabling statistics.
510 CollectPerServiceEnablingStatistics(notifier_id, enabled);
512 return;
515 void ChromeNotifierService::CollectPerServiceEnablingStatistics(
516 const std::string& notifier_id,
517 bool enabled) {
518 // TODO(petewil) - This approach does not scale well as we add new services,
519 // but we are limited to using predefined ENUM values in histogram based UMA
520 // data, which does not permit arbitrary strings.
521 // Find a way to make it scale, or remove enum value this when we have enough
522 // data.
524 ChromeNotifierServiceActionType action =
525 CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN;
527 // Derive action type from notifier_id and enabled.
528 // TODO(petewil): Add more sending services as they are enabled.
529 if (notifier_id == std::string(kFirstSyncedNotificationServiceId)) {
530 action = enabled
531 ? CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED
532 : CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED;
535 UMA_HISTOGRAM_ENUMERATION("ChromeNotifierService.Actions",
536 action,
537 CHROME_NOTIFIER_SERVICE_ACTION_COUNT);
540 void ChromeNotifierService::BuildServiceListValueInplace(
541 std::set<std::string> services, base::ListValue* list_value) {
542 std::set<std::string>::iterator iter;
544 // Iterate over the strings, adding each one to the list value
545 for (iter = services.begin();
546 iter != services.end();
547 ++iter) {
548 base::StringValue* string_value(new base::StringValue(*iter));
549 list_value->Append(string_value);
554 void ChromeNotifierService::DisplayUnreadNotificationsFromSource(
555 const std::string& notifier_id) {
556 for (std::vector<SyncedNotification*>::const_iterator iter =
557 notification_data_.begin();
558 iter != notification_data_.end();
559 ++iter) {
560 if ((*iter)->GetSendingServiceId() == notifier_id &&
561 (*iter)->GetReadState() == SyncedNotification::kUnread)
562 Display(*iter);
566 void ChromeNotifierService::RemoveUnreadNotificationsFromSource(
567 const std::string& notifier_id) {
568 for (std::vector<SyncedNotification*>::const_iterator iter =
569 notification_data_.begin();
570 iter != notification_data_.end();
571 ++iter) {
572 if ((*iter)->GetSendingServiceId() == notifier_id &&
573 (*iter)->GetReadState() == SyncedNotification::kUnread) {
574 notification_manager_->CancelById((*iter)->GetKey());
579 void ChromeNotifierService::OnEnabledSendingServiceListPrefChanged(
580 std::set<std::string>* ids_field) {
581 ids_field->clear();
582 const std::vector<std::string> pref_list =
583 enabled_sending_services_prefs_.GetValue();
584 for (size_t i = 0; i < pref_list.size(); ++i) {
585 std::string element = pref_list[i];
586 if (!element.empty())
587 ids_field->insert(element);
588 else
589 LOG(WARNING) << i << "-th element is not a string "
590 << prefs::kEnabledSyncedNotificationSendingServices;
594 void ChromeNotifierService::OnInitializedSendingServiceListPrefChanged(
595 std::set<std::string>* ids_field) {
596 ids_field->clear();
597 const std::vector<std::string> pref_list =
598 initialized_sending_services_prefs_.GetValue();
599 for (size_t i = 0; i < pref_list.size(); ++i) {
600 std::string element = pref_list[i];
601 if (!element.empty())
602 ids_field->insert(element);
603 else
604 LOG(WARNING) << i << "-th element is not a string for "
605 << prefs::kInitializedSyncedNotificationSendingServices;
609 void ChromeNotifierService::OnSyncedNotificationFirstRunBooleanPrefChanged(
610 bool* new_value) {
611 synced_notification_first_run_ = *new_value;
614 void ChromeNotifierService::RegisterProfilePrefs(
615 user_prefs::PrefRegistrySyncable* registry) {
616 // Register the pref for the list of enabled services.
617 registry->RegisterListPref(
618 prefs::kEnabledSyncedNotificationSendingServices,
619 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
620 // Register the pref for the list of initialized services.
621 registry->RegisterListPref(
622 prefs::kInitializedSyncedNotificationSendingServices,
623 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
624 // Register the preference for first run status, defaults to "true",
625 // meaning that this is the first run of the Synced Notification feature.
626 registry->RegisterBooleanPref(
627 prefs::kSyncedNotificationFirstRun, true,
628 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
631 void ChromeNotifierService::InitializePrefs() {
632 // Set up any pref changes to update our list of services.
633 enabled_sending_services_prefs_.Init(
634 prefs::kEnabledSyncedNotificationSendingServices,
635 profile_->GetPrefs(),
636 base::Bind(
637 &ChromeNotifierService::OnEnabledSendingServiceListPrefChanged,
638 base::Unretained(this),
639 base::Unretained(&enabled_sending_services_)));
640 initialized_sending_services_prefs_.Init(
641 prefs::kInitializedSyncedNotificationSendingServices,
642 profile_->GetPrefs(),
643 base::Bind(
644 &ChromeNotifierService::OnInitializedSendingServiceListPrefChanged,
645 base::Unretained(this),
646 base::Unretained(&initialized_sending_services_)));
647 synced_notification_first_run_prefs_.Init(
648 prefs::kSyncedNotificationFirstRun,
649 profile_->GetPrefs(),
650 base::Bind(
651 &ChromeNotifierService::
652 OnSyncedNotificationFirstRunBooleanPrefChanged,
653 base::Unretained(this),
654 base::Unretained(&synced_notification_first_run_)));
656 // Get the prefs from last session into our memeber varilables
657 OnEnabledSendingServiceListPrefChanged(&enabled_sending_services_);
658 OnInitializedSendingServiceListPrefChanged(&initialized_sending_services_);
660 synced_notification_first_run_ =
661 profile_->GetPrefs()->GetBoolean(prefs::kSyncedNotificationFirstRun);
664 void ChromeNotifierService::AddNewSendingServices() {
665 // TODO(petewil): When we have the new sync datatype for senders, use it
666 // instead of hardcoding the service name.
668 // Check to see if all known services are in the initialized list.
669 // If so, we can exit.
670 std::set<std::string>::iterator iter;
671 std::string first_synced_notification_service_id(
672 kFirstSyncedNotificationServiceId);
674 iter = find(initialized_sending_services_.begin(),
675 initialized_sending_services_.end(),
676 first_synced_notification_service_id);
677 if (initialized_sending_services_.end() != iter)
678 return;
680 // Build a ListValue with the list of services to be enabled.
681 base::ListValue enabled_sending_services;
682 base::ListValue initialized_sending_services;
684 // Mark any new services as enabled in preferences.
685 enabled_sending_services_.insert(first_synced_notification_service_id);
686 BuildServiceListValueInplace(enabled_sending_services_,
687 &enabled_sending_services);
688 profile_->GetPrefs()->Set(
689 prefs::kEnabledSyncedNotificationSendingServices,
690 enabled_sending_services);
691 // Mark it as having been initialized, so we don't try to turn it on again.
692 initialized_sending_services_.insert(first_synced_notification_service_id);
693 BuildServiceListValueInplace(initialized_sending_services_,
694 &initialized_sending_services);
695 profile_->GetPrefs()->Set(
696 prefs::kInitializedSyncedNotificationSendingServices,
697 initialized_sending_services);
700 } // namespace notifier