chrome_notifier_service.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The ChromeNotifierService works together with sync to maintain the state of
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// user notifications, which can then be presented in the notification center,
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// via the Notification UI Manager.
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include <string>
12a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include <vector>
13a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
142385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "base/command_line.h"
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/metrics/histogram.h"
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/prefs/pref_service.h"
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/values.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/notifications/desktop_notification_service.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/notifications/desktop_notification_service_factory.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification_ui_manager.h"
222385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/common/pref_names.h"
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h"
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
28a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "grit/generated_resources.h"
29a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "grit/theme_resources.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change_processor.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_error_factory.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/sync.pb.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/synced_notification_specifics.pb.h"
357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebTextDirection.h"
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/l10n/l10n_util.h"
37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "ui/base/resource/resource_bundle.h"
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/message_center/notifier_settings.h"
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)using content::UserMetricsAction;
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace notifier {
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
45a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst char kFirstSyncedNotificationServiceId[] = "Google+";
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ChromeNotifierService::avoid_bitmap_fetching_for_test_ = false;
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::ChromeNotifierService(Profile* profile,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             NotificationUIManager* manager)
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : profile_(profile), notification_manager_(manager),
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      synced_notification_first_run_(false) {
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  InitializePrefs();
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  AddNewSendingServices();
55a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::~ChromeNotifierService() {}
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Methods from BrowserContextKeyedService.
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChromeNotifierService::Shutdown() {}
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// syncer::SyncableService implementation.
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is called at startup to sync with the server.
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This code is not thread safe.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::ModelType type,
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const syncer::SyncDataList& initial_sync_data,
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<syncer::SyncErrorFactory> error_handler) {
70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A list of local changes to send up to the sync server.
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_ = sync_processor.Pass();
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != initial_sync_data.end(); ++it) {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncData& sync_data = *it;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Build a local notification object from the sync data.
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData(
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sync_data));
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!incoming) {
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // TODO(petewil): Turn this into a NOTREACHED() call once we fix the
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // underlying problem causing bad data.
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      LOG(WARNING) << "Badly formed sync data in incoming notification";
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Process each incoming remote notification.
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key = incoming->GetKey();
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_GT(key.length(), 0U);
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SyncedNotification* found = FindNotificationById(key);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (NULL == found) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If there are no conflicts, copy in the data from remote.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Add(incoming.Pass());
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the incoming (remote) and stored (local) notifications match
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // in all fields, we don't need to do anything here.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (incoming->EqualsIgnoringReadState(*found)) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (incoming->GetReadState() == found->GetReadState()) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Notification matches on the client and the server, nothing to do.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } else  {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If the read state is different, read wins for both places.
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          if (incoming->GetReadState() == SyncedNotification::kDismissed) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the server, but not the client.
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            found->NotificationHasBeenDismissed();
113ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // Tell the Notification UI Manager to remove it.
114ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            notification_manager_->CancelById(found->GetKey());
115ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          } else if (incoming->GetReadState() == SyncedNotification::kRead) {
116ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // If it is marked as read on the server, but not the client.
117ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            found->NotificationHasBeenRead();
118ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // Tell the Notification UI Manager to remove it.
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            notification_manager_->CancelById(found->GetKey());
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else {
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the client, but not the server.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer::SyncData sync_data = CreateSyncDataFromNotification(*found);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            new_changes.push_back(
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                syncer::SyncChange(FROM_HERE,
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   syncer::SyncChange::ACTION_UPDATE,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   sync_data));
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If local state changed, notify Notification UI Manager.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // For any other conflict besides read state, treat it as an update.
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // If different, just replace the local with the remote.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(petewil): Someday we may allow changes from the client to
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // flow upwards, when we do, we will need better merge resolution.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        found->Update(sync_data);
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        // Tell the notification manager to update the notification.
138ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(found);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_changes.size() > 0) {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    merge_result.set_error(sync_processor_->ProcessSyncChanges(
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, new_changes));
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Once we complete our first sync, we mark "first run" as false,
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // subsequent runs of Synced Notifications will get normal treatment.
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (synced_notification_first_run_) {
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    synced_notification_first_run_ = false;
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->SetBoolean(prefs::kSyncedNotificationFirstRun, false);
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return merge_result;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::StopSyncing(syncer::ModelType type) {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Since this data type is not user-unselectable, we chose not to implement
162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the stop syncing method, and instead do nothing here.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncDataList ChromeNotifierService::GetAllSyncData(
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::ModelType type) const {
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncDataList sync_data;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy our native format data into a SyncDataList format.
171ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::const_iterator it =
172ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.begin();
173ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_data.push_back(CreateSyncDataFromNotification(**it));
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return sync_data;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This method is called when there is an incoming sync change from the server.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncError ChromeNotifierService::ProcessSyncChanges(
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const tracked_objects::Location& from_here,
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const syncer::SyncChangeList& change_list) {
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncError error;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncChangeList::const_iterator it = change_list.begin();
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != change_list.end(); ++it) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncData sync_data = it->sync_data();
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncChange::SyncChangeType change_type = it->change_type();
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> new_notification(
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        CreateNotificationFromSyncData(sync_data));
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!new_notification.get()) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Failed to read notification.";
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
200ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& key = new_notification->GetKey();
201ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    DCHECK_GT(key.length(), 0U);
202ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* found = FindNotificationById(key);
203ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (change_type) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case syncer::SyncChange::ACTION_ADD:
206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Intentional fall through, cases are identical.
207ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      case syncer::SyncChange::ACTION_UPDATE:
208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if (found == NULL) {
209ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          Add(new_notification.Pass());
210ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          break;
211ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        }
212ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Update it in our store.
213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        found->Update(sync_data);
214ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Tell the notification manager to update the notification.
215ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(found);
216ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        break;
217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
218ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      case syncer::SyncChange::ACTION_DELETE:
219ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if (found == NULL) {
220ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          break;
221ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        }
222ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Remove it from our store.
223ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        FreeNotificationById(key);
224ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Remove it from the message center.
225ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(new_notification.get());
226ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // TODO(petewil): Do I need to remember that it was deleted in case the
227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // add arrives after the delete?  If so, how long do I need to remember?
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
231ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        NOTREACHED();
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error;
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Support functions for data type conversion.
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static method.  Get to the sync data in our internal format.
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification(
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncedNotification& notification) {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Construct the sync_data using the specifics from the notification.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return syncer::SyncData::CreateLocalData(
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      notification.GetKey(), notification.GetKey(),
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      notification.GetEntitySpecifics());
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static Method.  Convert from SyncData to our internal format.
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<SyncedNotification>
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ChromeNotifierService::CreateNotificationFromSyncData(
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const syncer::SyncData& sync_data) {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get a pointer to our data within the sync_data object.
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_pb::SyncedNotificationSpecifics specifics =
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_data.GetSpecifics().synced_notification();
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for mandatory fields in the sync_data object.
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!specifics.has_coalesced_notification() ||
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !specifics.coalesced_notification().has_key() ||
261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !specifics.coalesced_notification().has_read_state()) {
262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification missing mandatory fields "
263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << "has coalesced notification? "
264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.has_coalesced_notification()
265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has key? " << specifics.coalesced_notification().has_key()
266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has read state? "
267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.coalesced_notification().has_read_state();
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_unread_notification =
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kUnread &&
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       specifics.coalesced_notification().has_render_info());
276ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool is_well_formed_read_notification =
277ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      (static_cast<SyncedNotification::ReadState>(
278ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          specifics.coalesced_notification().read_state()) ==
279424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)       SyncedNotification::kRead);
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_dismissed_notification =
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kDismissed);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the notification is poorly formed, return a null pointer.
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_well_formed_unread_notification &&
287ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      !is_well_formed_read_notification &&
288b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !is_well_formed_dismissed_notification) {
289b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification is not well formed."
290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " unread well formed? "
291b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << is_well_formed_unread_notification
292b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " dismissed well formed? "
293ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << is_well_formed_dismissed_notification
294ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << " read well formed? "
295ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << is_well_formed_read_notification;
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
297b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a new notification object based on the supplied sync_data.
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SyncedNotification> notification(
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new SyncedNotification(sync_data));
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return notification.Pass();
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This returns a pointer into a vector that we own.  Caller must not free it.
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns NULL if no match is found.
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochSyncedNotification* ChromeNotifierService::FindNotificationById(
3097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& notification_id) {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): We can make a performance trade off here.
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // While the vector has good locality of reference, a map has faster lookup.
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Based on how big we expect this to get, maybe change this to a map.
313ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::const_iterator it =
314ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.begin();
315ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncedNotification* notification = *it;
3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (notification_id == notification->GetKey())
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return *it;
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
324ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::FreeNotificationById(
325ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& notification_id) {
326ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::iterator it = notification_data_.begin();
327ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
328ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* notification = *it;
329ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (notification_id == notification->GetKey()) {
330ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.erase(it);
331ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return;
332ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
333ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
334ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
335ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ChromeNotifierService::GetSyncedNotificationServices(
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::vector<message_center::Notifier*>* notifiers) {
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(mukai|petewil): Check the profile's eligibility before adding the
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // sample app.
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
341a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // TODO(petewil): Really obtain the list of synced notification sending
342a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // services from the server and create the list of ids here.  Until then, we
343a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // are hardcoding the service names.  Once that is done, remove this
344a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // hardcoding.
345a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // crbug.com/248337
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DesktopNotificationService* desktop_notification_service =
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      DesktopNotificationServiceFactory::GetForProfile(profile_);
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  message_center::NotifierId notifier_id(
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      message_center::NotifierId::SYNCED_NOTIFICATION_SERVICE,
350a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      kFirstSyncedNotificationServiceId);
351a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  message_center::Notifier* notifier_service = new message_center::Notifier(
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      notifier_id,
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      l10n_util::GetStringUTF16(
354a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch          IDS_FIRST_SYNCED_NOTIFICATION_SERVICE_NAME),
355a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      desktop_notification_service->IsNotifierEnabled(notifier_id));
356a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
357a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Add icons for our sending services.
358a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // TODO(petewil): Replace this temporary hardcoding with a new sync datatype
359a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // to dynamically get the name and icon for each synced notification sending
360a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // service.  Until then, we use hardcoded service icons for all services.
361a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // crbug.com/248337
362a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  notifier_service->icon = ui::ResourceBundle::GetSharedInstance().
363a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      GetImageNamed(IDR_TEMPORARY_GOOGLE_PLUS_ICON);
364a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
365d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Enable or disable the sending service per saved settings.
366d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
367d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
368d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  iter = find(enabled_sending_services_.begin(),
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              enabled_sending_services_.end(),
370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              notifier_id.id);
371d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (iter != enabled_sending_services_.end())
372d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    notifier_service->enabled = true;
373d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  else
374d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    notifier_service->enabled = false;
375d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
376a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  notifiers->push_back(notifier_service);
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
379ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::MarkNotificationAsRead(
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key) {
381a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
3827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  SyncedNotification* notification = FindNotificationById(key);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(notification != NULL);
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
385ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification->NotificationHasBeenRead();
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  new_changes.push_back(
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::SyncChange(FROM_HERE,
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         syncer::SyncChange::ACTION_UPDATE,
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         sync_data));
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Add a new notification to our data structure.  This takes ownership
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the passed in pointer.
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncedNotification* notification_copy = notification.get();
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Take ownership of the object and put it into our local storage.
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification_data_.push_back(notification.release());
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // If the user is not interested in this type of notification, ignore it.
406d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter =
407a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      find(enabled_sending_services_.begin(),
408a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch           enabled_sending_services_.end(),
409a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch           notification_copy->GetSendingServiceId());
410a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (iter == enabled_sending_services_.end()) {
411a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return;
412a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
413a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
414ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  UpdateInMessageCenter(notification_copy);
4157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ChromeNotifierService::AddForTest(
4187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scoped_ptr<notifier::SyncedNotification> notification) {
419ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification_data_.push_back(notification.release());
420ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
422ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::UpdateInMessageCenter(
423ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* notification) {
4242385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  // If the feature is disabled, exit now.
4252385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  if (!notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
426ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      CommandLine::ForCurrentProcess()))
4272385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return;
428a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
429ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification->LogNotification();
430ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
431ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (notification->GetReadState() == SyncedNotification::kUnread) {
432ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the message is unread, update it.
433ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    Display(notification);
434ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  } else {
435ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the message is read or deleted, dismiss it from the center.
436ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // We intentionally ignore errors if it is not in the center.
437ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    notification_manager_->CancelById(notification->GetKey());
438ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
439ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
440ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
441ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::Display(SyncedNotification* notification) {
442868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set up to fetch the bitmaps.
4437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  notification->QueueBitmapFetchJobs(notification_manager_,
444ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                     this,
445ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                     profile_);
446868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
447868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Our tests cannot use the network for reliability reasons.
448868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (avoid_bitmap_fetching_for_test_) {
449868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
451868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If this is the first run for the feature, don't surprise the user.
4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Instead, place all backlogged notifications into the notification
4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // center.
4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (synced_notification_first_run_) {
4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Setting the toast state to false will prevent toasting the notification.
4574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    notification->SetToastState(false);
4584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
460868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Start the bitmap fetching, Show() will be called when the last bitmap
461868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // either arrives or times out.
4627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  notification->StartBitmapFetch();
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ChromeNotifierService::OnSyncedNotificationServiceEnabled(
466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& notifier_id, bool enabled) {
467d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
468d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
469d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Make a copy of the notifier_id, which might not have lifetime long enough
470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // for this function to finish all of its work.
471d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string notifier_id_copy(notifier_id);
472a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
473a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  iter = find(enabled_sending_services_.begin(),
474a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch              enabled_sending_services_.end(),
475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              notifier_id_copy);
476d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
4774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue synced_notification_services;
478a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
479a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Add the notifier_id if it is enabled and not already there.
480a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (iter == enabled_sending_services_.end() && enabled) {
481d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    enabled_sending_services_.insert(notifier_id_copy);
4823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Check now for any outstanding notifications.
4833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DisplayUnreadNotificationsFromSource(notifier_id);
484d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    BuildServiceListValueInplace(enabled_sending_services_,
485d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 &synced_notification_services);
486d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Add this preference to the enabled list.
4874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
4884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              synced_notification_services);
489a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Remove the notifier_id if it is disabled and present.
490a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  } else if (iter != enabled_sending_services_.end() && !enabled) {
491a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    enabled_sending_services_.erase(iter);
492d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    BuildServiceListValueInplace(enabled_sending_services_,
493d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 &synced_notification_services);
494d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Remove this peference from the enabled list.
4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
4964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              synced_notification_services);
497d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    RemoveUnreadNotificationsFromSource(notifier_id_copy);
498a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
499a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
5008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Collect UMA statistics when a service is enabled or disabled.
5018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (enabled) {
5028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::RecordAction(
5038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        UserMetricsAction("SyncedNotifications.SendingServiceEnabled"));
5048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } else {
5058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::RecordAction(
5068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        UserMetricsAction("SyncedNotifications.SendingServiceDisabled"));
5078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
5088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Collect individual service enabling/disabling statistics.
5108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CollectPerServiceEnablingStatistics(notifier_id, enabled);
5118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
512a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return;
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ChromeNotifierService::CollectPerServiceEnablingStatistics(
5168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::string& notifier_id,
5178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool enabled) {
5188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(petewil) - This approach does not scale well as we add new services,
5198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // but we are limited to using predefined ENUM values in histogram based UMA
5208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // data, which does not permit arbitrary strings.
5218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find a way to make it scale, or remove enum value this when we have enough
5228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // data.
5238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ChromeNotifierServiceActionType action =
5258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN;
5268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Derive action type from notifier_id and enabled.
5288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(petewil): Add more sending services as they are enabled.
5298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (notifier_id == std::string(kFirstSyncedNotificationServiceId)) {
5308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    action = enabled
5318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        ? CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED
5328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        : CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED;
5338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
5348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ChromeNotifierService.Actions",
5368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            action,
5378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            CHROME_NOTIFIER_SERVICE_ACTION_COUNT);
5388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
540d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::BuildServiceListValueInplace(
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::set<std::string> services, base::ListValue* list_value) {
542d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
543d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Iterate over the strings, adding each one to the list value
545d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (iter = services.begin();
546d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       iter != services.end();
547d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       ++iter) {
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::StringValue* string_value(new base::StringValue(*iter));
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    list_value->Append(string_value);
550d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
551d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
552d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
553d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeNotifierService::DisplayUnreadNotificationsFromSource(
555d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& notifier_id) {
5563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator iter =
5573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          notification_data_.begin();
5583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != notification_data_.end();
5593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter) {
5603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if ((*iter)->GetSendingServiceId() == notifier_id &&
5613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        (*iter)->GetReadState() == SyncedNotification::kUnread)
5623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Display(*iter);
5633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeNotifierService::RemoveUnreadNotificationsFromSource(
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& notifier_id) {
5683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator iter =
5693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          notification_data_.begin();
5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != notification_data_.end();
5713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter) {
5723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if ((*iter)->GetSendingServiceId() == notifier_id &&
573d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        (*iter)->GetReadState() == SyncedNotification::kUnread) {
5743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      notification_manager_->CancelById((*iter)->GetKey());
575d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
5763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
579d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::OnEnabledSendingServiceListPrefChanged(
580d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::set<std::string>* ids_field) {
581d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ids_field->clear();
582d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::vector<std::string> pref_list =
583d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      enabled_sending_services_prefs_.GetValue();
584d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (size_t i = 0; i < pref_list.size(); ++i) {
585d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string element = pref_list[i];
586d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!element.empty())
587d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ids_field->insert(element);
588d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
589d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(WARNING) << i << "-th element is not a string "
590d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   << prefs::kEnabledSyncedNotificationSendingServices;
591d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
592d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
593d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
594d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::OnInitializedSendingServiceListPrefChanged(
595d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::set<std::string>* ids_field) {
596d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ids_field->clear();
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::vector<std::string> pref_list =
598d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      initialized_sending_services_prefs_.GetValue();
599d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (size_t i = 0; i < pref_list.size(); ++i) {
600d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string element = pref_list[i];
601d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!element.empty())
602d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ids_field->insert(element);
603d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
604d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(WARNING) << i << "-th element is not a string for "
605d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   << prefs::kInitializedSyncedNotificationSendingServices;
606d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
607d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
608d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ChromeNotifierService::OnSyncedNotificationFirstRunBooleanPrefChanged(
6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    bool* new_value) {
6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_ = *new_value;
6124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
614d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::RegisterProfilePrefs(
615d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
616d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Register the pref for the list of enabled services.
617d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  registry->RegisterListPref(
618d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
619d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
620d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Register the pref for the list of initialized services.
621d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  registry->RegisterListPref(
622d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
623d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
6244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Register the preference for first run status, defaults to "true",
6254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // meaning that this is the first run of the Synced Notification feature.
6264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registry->RegisterBooleanPref(
6274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kSyncedNotificationFirstRun, true,
6284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
629d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
630d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
631d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::InitializePrefs() {
632d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Set up any pref changes to update our list of services.
633d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  enabled_sending_services_prefs_.Init(
634d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
635d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_->GetPrefs(),
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &ChromeNotifierService::OnEnabledSendingServiceListPrefChanged,
638d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(this),
639d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(&enabled_sending_services_)));
640d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  initialized_sending_services_prefs_.Init(
641d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
642d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_->GetPrefs(),
643d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(
644d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &ChromeNotifierService::OnInitializedSendingServiceListPrefChanged,
645d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(this),
646d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(&initialized_sending_services_)));
6474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_prefs_.Init(
6484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kSyncedNotificationFirstRun,
6494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_->GetPrefs(),
6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(
6514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          &ChromeNotifierService::
6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              OnSyncedNotificationFirstRunBooleanPrefChanged,
6534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          base::Unretained(this),
6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          base::Unretained(&synced_notification_first_run_)));
655d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
656d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Get the prefs from last session into our memeber varilables
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  OnEnabledSendingServiceListPrefChanged(&enabled_sending_services_);
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  OnInitializedSendingServiceListPrefChanged(&initialized_sending_services_);
6598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_ =
6614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_->GetPrefs()->GetBoolean(prefs::kSyncedNotificationFirstRun);
662d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
663d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
664d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::AddNewSendingServices() {
665d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // TODO(petewil): When we have the new sync datatype for senders, use it
666d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // instead of hardcoding the service name.
667d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Check to see if all known services are in the initialized list.
669d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // If so, we can exit.
670d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string first_synced_notification_service_id(
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      kFirstSyncedNotificationServiceId);
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
674d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  iter = find(initialized_sending_services_.begin(),
675d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              initialized_sending_services_.end(),
676d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              first_synced_notification_service_id);
677d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (initialized_sending_services_.end() != iter)
678d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
679d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
680d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Build a ListValue with the list of services to be enabled.
6814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue enabled_sending_services;
6824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue initialized_sending_services;
683d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
684d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Mark any new services as enabled in preferences.
685d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  enabled_sending_services_.insert(first_synced_notification_service_id);
6864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BuildServiceListValueInplace(enabled_sending_services_,
6874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               &enabled_sending_services);
6884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_->GetPrefs()->Set(
6894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
6904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      enabled_sending_services);
691d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Mark it as having been initialized, so we don't try to turn it on again.
692d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  initialized_sending_services_.insert(first_synced_notification_service_id);
6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BuildServiceListValueInplace(initialized_sending_services_,
6944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               &initialized_sending_services);
6954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_->GetPrefs()->Set(
6964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
6974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      initialized_sending_services);
698d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
6993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace notifier
701