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