chrome_notifier_service.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <set>
12a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include <string>
13a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include <vector>
14a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
152385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "base/command_line.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/guid.h"
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/metrics/histogram.h"
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/prefs/pref_service.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/values.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/notifications/desktop_notification_service.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/notifications/desktop_notification_service_factory.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification_ui_manager.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h"
262385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/notifications/sync_notifier/welcome_delegate.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/common/pref_names.h"
30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h"
31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
33a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "grit/generated_resources.h"
34a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "grit/theme_resources.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change_processor.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_error_factory.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/sync.pb.h"
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/synced_notification_specifics.pb.h"
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebTextDirection.h"
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/l10n/l10n_util.h"
42a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "ui/base/resource/resource_bundle.h"
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/message_center/notifier_settings.h"
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UserMetricsAction;
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace notifier {
49a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst char kFirstSyncedNotificationServiceId[] = "Google+";
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kSyncedNotificationsWelcomeOrigin[] =
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "synced-notifications://welcome";
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// SyncedNotificationAppInfoTemp is a class that contains the information
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// necessary to produce a welcome notification and the app badges for all synced
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// notification.
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(dewittj): Convert this into a sync protobuf-backed data structure.
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class SyncedNotificationAppInfoTemp {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  explicit SyncedNotificationAppInfoTemp(const std::string& app_id,
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                         const base::string16& service_name);
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ~SyncedNotificationAppInfoTemp();
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& app_id() const { return app_id_; }
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16& service_name() const { return service_name_; }
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16& title() const { return title_; }
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void set_icon(const gfx::Image& icon) { icon_ = icon; }
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Image& icon() const { return icon_; }
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void set_small_icon(const gfx::Image& small_icon) {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    small_icon_ = small_icon;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Image& small_icon() const { return small_icon_; }
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const message_center::NotifierId GetNotifierId() const;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id_;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 service_name_;
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Image icon_;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Image small_icon_;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 title_;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 message_;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SyncedNotificationAppInfoTemp::SyncedNotificationAppInfoTemp(
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& service_name)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : app_id_(app_id), service_name_(service_name) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  title_ =
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringFUTF16(IDS_NOTIFIER_WELCOME_TITLE, service_name_);
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SyncedNotificationAppInfoTemp::~SyncedNotificationAppInfoTemp() {}
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const message_center::NotifierId SyncedNotificationAppInfoTemp::GetNotifierId()
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const {
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return message_center::NotifierId(
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::NotifierId::SYNCED_NOTIFICATION_SERVICE, app_id());
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ChromeNotifierService::avoid_bitmap_fetching_for_test_ = false;
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::ChromeNotifierService(Profile* profile,
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             NotificationUIManager* manager)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : profile_(profile),
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      notification_manager_(manager),
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      synced_notification_first_run_(false) {
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SyncedNotificationAppInfoTemp* temp_app_info =
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new SyncedNotificationAppInfoTemp(
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kFirstSyncedNotificationServiceId,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_FIRST_SYNCED_NOTIFICATION_SERVICE_NAME));
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  temp_app_info->set_small_icon(
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          IDR_TEMPORARY_GOOGLE_PLUS_ICON));
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  app_info_data_.push_back(temp_app_info);
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  InitializePrefs();
119a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::~ChromeNotifierService() {}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Methods from KeyedService.
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChromeNotifierService::Shutdown() {}
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// syncer::SyncableService implementation.
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is called at startup to sync with the server.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This code is not thread safe.
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type,
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncDataList& initial_sync_data,
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<syncer::SyncErrorFactory> error_handler) {
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  thread_checker_.CalledOnValidThread();
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A list of local changes to send up to the sync server.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_ = sync_processor.Pass();
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != initial_sync_data.end(); ++it) {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncData& sync_data = *it;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Build a local notification object from the sync data.
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData(
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sync_data));
150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!incoming) {
151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // TODO(petewil): Turn this into a NOTREACHED() call once we fix the
152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // underlying problem causing bad data.
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      LOG(WARNING) << "Badly formed sync data in incoming notification";
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Process each incoming remote notification.
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key = incoming->GetKey();
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_GT(key.length(), 0U);
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SyncedNotification* found = FindNotificationById(key);
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (NULL == found) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If there are no conflicts, copy in the data from remote.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Add(incoming.Pass());
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the incoming (remote) and stored (local) notifications match
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // in all fields, we don't need to do anything here.
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (incoming->EqualsIgnoringReadState(*found)) {
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (incoming->GetReadState() == found->GetReadState()) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Notification matches on the client and the server, nothing to do.
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } else {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If the read state is different, read wins for both places.
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          if (incoming->GetReadState() == SyncedNotification::kDismissed) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the server, but not the client.
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            found->NotificationHasBeenDismissed();
178ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // Tell the Notification UI Manager to remove it.
179ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            notification_manager_->CancelById(found->GetKey());
180ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          } else if (incoming->GetReadState() == SyncedNotification::kRead) {
181ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // If it is marked as read on the server, but not the client.
182ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            found->NotificationHasBeenRead();
183ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // Tell the Notification UI Manager to remove it.
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            notification_manager_->CancelById(found->GetKey());
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the client, but not the server.
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer::SyncData sync_data = CreateSyncDataFromNotification(*found);
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            new_changes.push_back(
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                syncer::SyncChange(FROM_HERE,
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   syncer::SyncChange::ACTION_UPDATE,
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   sync_data));
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If local state changed, notify Notification UI Manager.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // If different, just replace the local with the remote.
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(petewil): Someday we may allow changes from the client to
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // flow upwards, when we do, we will need better merge resolution.
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        found->Update(sync_data);
2007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        // Tell the notification manager to update the notification.
202ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(found);
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_changes.size() > 0) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    merge_result.set_error(sync_processor_->ProcessSyncChanges(
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, new_changes));
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Once we complete our first sync, we mark "first run" as false,
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // subsequent runs of Synced Notifications will get normal treatment.
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (synced_notification_first_run_) {
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    synced_notification_first_run_ = false;
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->SetBoolean(prefs::kSyncedNotificationFirstRun, false);
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return merge_result;
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::StopSyncing(syncer::ModelType type) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Since this data type is not user-unselectable, we chose not to implement
226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the stop syncing method, and instead do nothing here.
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncDataList ChromeNotifierService::GetAllSyncData(
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type) const {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncDataList sync_data;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy our native format data into a SyncDataList format.
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::const_iterator it =
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.begin();
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_data.push_back(CreateSyncDataFromNotification(**it));
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return sync_data;
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This method is called when there is an incoming sync change from the server.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncError ChromeNotifierService::ProcessSyncChanges(
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const tracked_objects::Location& from_here,
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncChangeList& change_list) {
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  thread_checker_.CalledOnValidThread();
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncError error;
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncChangeList::const_iterator it = change_list.begin();
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != change_list.end(); ++it) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncData sync_data = it->sync_data();
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncChange::SyncChangeType change_type = it->change_type();
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> new_notification(
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        CreateNotificationFromSyncData(sync_data));
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!new_notification.get()) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Failed to read notification.";
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
264ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& key = new_notification->GetKey();
265ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    DCHECK_GT(key.length(), 0U);
266ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* found = FindNotificationById(key);
267ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (change_type) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case syncer::SyncChange::ACTION_ADD:
270ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Intentional fall through, cases are identical.
271ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      case syncer::SyncChange::ACTION_UPDATE:
272ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if (found == NULL) {
273ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          Add(new_notification.Pass());
274ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          break;
275ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        }
276ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Update it in our store.
277ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        found->Update(sync_data);
278ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Tell the notification manager to update the notification.
279ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(found);
280ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        break;
281ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
282ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      case syncer::SyncChange::ACTION_DELETE:
283ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if (found == NULL) {
284ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          break;
285ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        }
286ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Remove it from our store.
287ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        FreeNotificationById(key);
288ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Remove it from the message center.
289ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(new_notification.get());
290ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // TODO(petewil): Do I need to remember that it was deleted in case the
291ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // add arrives after the delete?  If so, how long do I need to remember?
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
295ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        NOTREACHED();
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error;
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Support functions for data type conversion.
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static method.  Get to the sync data in our internal format.
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification(
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncedNotification& notification) {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Construct the sync_data using the specifics from the notification.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return syncer::SyncData::CreateLocalData(
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      notification.GetKey(), notification.GetKey(),
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      notification.GetEntitySpecifics());
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static Method.  Convert from SyncData to our internal format.
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<SyncedNotification>
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ChromeNotifierService::CreateNotificationFromSyncData(
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncData& sync_data) {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get a pointer to our data within the sync_data object.
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_pb::SyncedNotificationSpecifics specifics =
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_data.GetSpecifics().synced_notification();
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for mandatory fields in the sync_data object.
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!specifics.has_coalesced_notification() ||
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !specifics.coalesced_notification().has_key() ||
325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !specifics.coalesced_notification().has_read_state()) {
326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification missing mandatory fields "
327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << "has coalesced notification? "
328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.has_coalesced_notification()
329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has key? " << specifics.coalesced_notification().has_key()
330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has read state? "
331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.coalesced_notification().has_read_state();
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_unread_notification =
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kUnread &&
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       specifics.coalesced_notification().has_render_info());
340ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool is_well_formed_read_notification =
341ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      (static_cast<SyncedNotification::ReadState>(
342ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          specifics.coalesced_notification().read_state()) ==
343424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)       SyncedNotification::kRead);
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_dismissed_notification =
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kDismissed);
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the notification is poorly formed, return a null pointer.
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_well_formed_unread_notification &&
351ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      !is_well_formed_read_notification &&
352b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !is_well_formed_dismissed_notification) {
353b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification is not well formed."
354b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " unread well formed? "
355b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << is_well_formed_unread_notification
356b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " dismissed well formed? "
357ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << is_well_formed_dismissed_notification
358ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << " read well formed? "
359ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << is_well_formed_read_notification;
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
361b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a new notification object based on the supplied sync_data.
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SyncedNotification> notification(
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new SyncedNotification(sync_data));
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return notification.Pass();
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This returns a pointer into a vector that we own.  Caller must not free it.
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns NULL if no match is found.
3727dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochSyncedNotification* ChromeNotifierService::FindNotificationById(
3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& notification_id) {
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): We can make a performance trade off here.
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // While the vector has good locality of reference, a map has faster lookup.
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Based on how big we expect this to get, maybe change this to a map.
377ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::const_iterator it =
378ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.begin();
379ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncedNotification* notification = *it;
3817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (notification_id == notification->GetKey())
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return *it;
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
388ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::FreeNotificationById(
389ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& notification_id) {
390ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::iterator it = notification_data_.begin();
391ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
392ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* notification = *it;
393ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (notification_id == notification->GetKey()) {
394ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.erase(it);
395ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return;
396ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
397ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
398ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
399ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ChromeNotifierService::GetSyncedNotificationServices(
401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::vector<message_center::Notifier*>* notifiers) {
4027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(mukai|petewil): Check the profile's eligibility before adding the
4037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // sample app.
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScopedVector<SyncedNotificationAppInfoTemp>::iterator it =
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      app_info_data_.begin();
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; it != app_info_data_.end(); ++it) {
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SyncedNotificationAppInfoTemp* app_info = *it;
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_center::NotifierId notifier_id = app_info->GetNotifierId();
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Enable or disable the sending service per saved settings.
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool app_enabled = false;
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::set<std::string>::iterator iter;
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    iter = find(enabled_sending_services_.begin(),
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                enabled_sending_services_.end(),
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                notifier_id.id);
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_enabled = iter != enabled_sending_services_.end();
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_center::Notifier* app_info_notifier = new message_center::Notifier(
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        notifier_id, app_info->service_name(), app_enabled);
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_info_notifier->icon = app_info->small_icon();
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // |notifiers| takes ownership of |app_info_notifier|.
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    notifiers->push_back(app_info_notifier);
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
428ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::MarkNotificationAsRead(
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key) {
430a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
4317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  SyncedNotification* notification = FindNotificationById(key);
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(notification != NULL);
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
434ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification->NotificationHasBeenRead();
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  new_changes.push_back(
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::SyncChange(FROM_HERE,
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         syncer::SyncChange::ACTION_UPDATE,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         sync_data));
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Add a new notification to our data structure.  This takes ownership
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the passed in pointer.
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncedNotification* notification_copy = notification.get();
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Take ownership of the object and put it into our local storage.
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification_data_.push_back(notification.release());
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
454a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // If the user is not interested in this type of notification, ignore it.
455d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter =
456a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      find(enabled_sending_services_.begin(),
457a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch           enabled_sending_services_.end(),
458a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch           notification_copy->GetSendingServiceId());
459a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (iter == enabled_sending_services_.end()) {
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    iter = find(initialized_sending_services_.begin(),
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                initialized_sending_services_.end(),
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                notification_copy->GetSendingServiceId());
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (iter != initialized_sending_services_.end())
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
465a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
466a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
467ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  UpdateInMessageCenter(notification_copy);
4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ChromeNotifierService::AddForTest(
4717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scoped_ptr<notifier::SyncedNotification> notification) {
472ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification_data_.push_back(notification.release());
473ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
4747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
475ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::UpdateInMessageCenter(
476ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* notification) {
4772385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  // If the feature is disabled, exit now.
4782385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  if (!notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
479ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      CommandLine::ForCurrentProcess()))
4802385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return;
481a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
482ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification->LogNotification();
483ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
484ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (notification->GetReadState() == SyncedNotification::kUnread) {
485ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the message is unread, update it.
486ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    Display(notification);
487ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  } else {
488ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the message is read or deleted, dismiss it from the center.
489ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // We intentionally ignore errors if it is not in the center.
490ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    notification_manager_->CancelById(notification->GetKey());
491ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
492ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
493ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
494ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::Display(SyncedNotification* notification) {
4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If this is the first run for the feature, don't surprise the user.
4964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Instead, place all backlogged notifications into the notification
4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // center.
4984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (synced_notification_first_run_) {
4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Setting the toast state to false will prevent toasting the notification.
5004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    notification->SetToastState(false);
5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Our tests cannot use the network for reliability reasons.
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (avoid_bitmap_fetching_for_test_) {
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    notification->Show(notification_manager_, this, profile_);
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Set up to fetch the bitmaps.
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  notification->QueueBitmapFetchJobs(notification_manager_, this, profile_);
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Start the bitmap fetching, Show() will be called when the last bitmap
513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // either arrives or times out.
5147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  notification->StartBitmapFetch();
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ChromeNotifierService::OnSyncedNotificationServiceEnabled(
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& notifier_id, bool enabled) {
519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
520d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
521d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Make a copy of the notifier_id, which might not have lifetime long enough
522d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // for this function to finish all of its work.
523d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string notifier_id_copy(notifier_id);
524a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
525a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  iter = find(enabled_sending_services_.begin(),
526a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch              enabled_sending_services_.end(),
527d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              notifier_id_copy);
528d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue synced_notification_services;
530a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
531a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Add the notifier_id if it is enabled and not already there.
532a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (iter == enabled_sending_services_.end() && enabled) {
533d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    enabled_sending_services_.insert(notifier_id_copy);
5343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Check now for any outstanding notifications.
5353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DisplayUnreadNotificationsFromSource(notifier_id);
536d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    BuildServiceListValueInplace(enabled_sending_services_,
537d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 &synced_notification_services);
538d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Add this preference to the enabled list.
5394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
5404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              synced_notification_services);
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Remove the notifier_id if it is disabled and present.
542a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  } else if (iter != enabled_sending_services_.end() && !enabled) {
543a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    enabled_sending_services_.erase(iter);
544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    BuildServiceListValueInplace(enabled_sending_services_,
545d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 &synced_notification_services);
546d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Remove this peference from the enabled list.
5474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              synced_notification_services);
549d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    RemoveUnreadNotificationsFromSource(notifier_id_copy);
550a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
551a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
5528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Collect UMA statistics when a service is enabled or disabled.
5538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (enabled) {
5548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::RecordAction(
5558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        UserMetricsAction("SyncedNotifications.SendingServiceEnabled"));
5568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } else {
5578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::RecordAction(
5588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        UserMetricsAction("SyncedNotifications.SendingServiceDisabled"));
5598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
5608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Collect individual service enabling/disabling statistics.
5628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CollectPerServiceEnablingStatistics(notifier_id, enabled);
5638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
564a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return;
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ChromeNotifierService::CollectPerServiceEnablingStatistics(
5688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::string& notifier_id,
5698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool enabled) {
5708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(petewil) - This approach does not scale well as we add new services,
5718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // but we are limited to using predefined ENUM values in histogram based UMA
5728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // data, which does not permit arbitrary strings.
5738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find a way to make it scale, or remove enum value this when we have enough
5748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // data.
5758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ChromeNotifierServiceActionType action =
5778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN;
5788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Derive action type from notifier_id and enabled.
5808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(petewil): Add more sending services as they are enabled.
5818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (notifier_id == std::string(kFirstSyncedNotificationServiceId)) {
5828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    action = enabled
5838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        ? CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED
5848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        : CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED;
5858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
5868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ChromeNotifierService.Actions",
5888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            action,
5898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            CHROME_NOTIFIER_SERVICE_ACTION_COUNT);
5908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
592d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::BuildServiceListValueInplace(
5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::set<std::string> services, base::ListValue* list_value) {
594d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
595d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
596d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Iterate over the strings, adding each one to the list value
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (iter = services.begin();
598d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       iter != services.end();
599d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       ++iter) {
6004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::StringValue* string_value(new base::StringValue(*iter));
6014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    list_value->Append(string_value);
602d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
603d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
604d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeNotifierService::DisplayUnreadNotificationsFromSource(
606d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& notifier_id) {
6073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator iter =
6083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          notification_data_.begin();
6093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != notification_data_.end();
6103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter) {
6113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if ((*iter)->GetSendingServiceId() == notifier_id &&
6123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        (*iter)->GetReadState() == SyncedNotification::kUnread)
6133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Display(*iter);
6143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeNotifierService::RemoveUnreadNotificationsFromSource(
618d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& notifier_id) {
6193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator iter =
6203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          notification_data_.begin();
6213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != notification_data_.end();
6223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter) {
6233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if ((*iter)->GetSendingServiceId() == notifier_id &&
624d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        (*iter)->GetReadState() == SyncedNotification::kUnread) {
6253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      notification_manager_->CancelById((*iter)->GetKey());
626d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
6273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
6283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
630d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::OnEnabledSendingServiceListPrefChanged(
631d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::set<std::string>* ids_field) {
632d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ids_field->clear();
633d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::vector<std::string> pref_list =
634d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      enabled_sending_services_prefs_.GetValue();
635d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (size_t i = 0; i < pref_list.size(); ++i) {
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string element = pref_list[i];
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!element.empty())
638d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ids_field->insert(element);
639d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
640d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(WARNING) << i << "-th element is not a string "
641d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   << prefs::kEnabledSyncedNotificationSendingServices;
642d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
643d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
644d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
645d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::OnInitializedSendingServiceListPrefChanged(
646d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::set<std::string>* ids_field) {
647d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ids_field->clear();
648d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::vector<std::string> pref_list =
649d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      initialized_sending_services_prefs_.GetValue();
650d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (size_t i = 0; i < pref_list.size(); ++i) {
651d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string element = pref_list[i];
652d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!element.empty())
653d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ids_field->insert(element);
654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
655d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(WARNING) << i << "-th element is not a string for "
656d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   << prefs::kInitializedSyncedNotificationSendingServices;
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
659d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ChromeNotifierService::OnSyncedNotificationFirstRunBooleanPrefChanged(
6614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    bool* new_value) {
6624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_ = *new_value;
6634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
665d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::RegisterProfilePrefs(
666d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
667d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Register the pref for the list of enabled services.
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  registry->RegisterListPref(
669d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Register the pref for the list of initialized services.
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  registry->RegisterListPref(
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
6754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Register the preference for first run status, defaults to "true",
6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // meaning that this is the first run of the Synced Notification feature.
6774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registry->RegisterBooleanPref(
6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kSyncedNotificationFirstRun, true,
6794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
680d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
681d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
682d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::InitializePrefs() {
683d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Set up any pref changes to update our list of services.
684d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  enabled_sending_services_prefs_.Init(
685d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
686d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_->GetPrefs(),
687d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(
688d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &ChromeNotifierService::OnEnabledSendingServiceListPrefChanged,
689d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(this),
690d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(&enabled_sending_services_)));
691d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  initialized_sending_services_prefs_.Init(
692d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
693d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_->GetPrefs(),
694d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(
695d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &ChromeNotifierService::OnInitializedSendingServiceListPrefChanged,
696d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(this),
697d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(&initialized_sending_services_)));
6984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_prefs_.Init(
6994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kSyncedNotificationFirstRun,
7004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_->GetPrefs(),
7014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(
7024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          &ChromeNotifierService::
7034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              OnSyncedNotificationFirstRunBooleanPrefChanged,
7044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          base::Unretained(this),
7054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          base::Unretained(&synced_notification_first_run_)));
706d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
707d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Get the prefs from last session into our memeber varilables
708d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  OnEnabledSendingServiceListPrefChanged(&enabled_sending_services_);
709d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  OnInitializedSendingServiceListPrefChanged(&initialized_sending_services_);
7108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
7114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_ =
7124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_->GetPrefs()->GetBoolean(prefs::kSyncedNotificationFirstRun);
713d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
714d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeNotifierService::ShowWelcomeToastIfNecessary(
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const SyncedNotification* synced_notification,
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NotificationUIManager* notification_ui_manager) {
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& sending_service_id =
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      synced_notification->GetSendingServiceId();
720d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
721d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
722d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  iter = find(initialized_sending_services_.begin(),
723d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              initialized_sending_services_.end(),
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              sending_service_id);
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If we already initialized the sending service, then return early since no
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // welcome toast is necessary.
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (iter != initialized_sending_services_.end())
729d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
730d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If there is no app info, we can't show a welcome toast.  Ideally all synced
7325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // notifications will be delayed until an app_info data structure can be
7335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // constructed for them.
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(dewittj): Refactor when app_info is populated asynchronously.
735a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SyncedNotificationAppInfoTemp* app_info = FindAppInfo(sending_service_id);
7365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!app_info)
7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(dewittj): Ensure that the app info icon is set before this point.
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_info->icon().IsEmpty()) {
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Image notification_app_icon = synced_notification->GetAppIcon();
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!notification_app_icon.IsEmpty()) {
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_info->set_icon(notification_app_icon);
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // This block should only be reached in tests since the downloads are
7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // already finished for |synced_notification|.
7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "Unable to find the app icon for the welcome notification. "
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << "Service ID: " << sending_service_id;
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_center::NotifierId notifier_id(
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::NotifierId::SYNCED_NOTIFICATION_SERVICE,
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sending_service_id);
7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Notification notification = CreateWelcomeNotificationForService(app_info);
7575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  notification_ui_manager->Add(notification, profile_);
7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enabled_sending_services_.insert(sending_service_id);
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  initialized_sending_services_.insert(sending_service_id);
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
762d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Build a ListValue with the list of services to be enabled.
7634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue enabled_sending_services;
7644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue initialized_sending_services;
765d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
766d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Mark any new services as enabled in preferences.
7674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BuildServiceListValueInplace(enabled_sending_services_,
7684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               &enabled_sending_services);
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            enabled_sending_services);
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Mark any new services as initialized in preferences.
7724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BuildServiceListValueInplace(initialized_sending_services_,
7734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               &initialized_sending_services);
7744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_->GetPrefs()->Set(
7754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
7764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      initialized_sending_services);
777d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
7783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
779a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SyncedNotificationAppInfoTemp* ChromeNotifierService::FindAppInfo(
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id) const {
781a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScopedVector<SyncedNotificationAppInfoTemp>::const_iterator iter =
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_info_data_.begin();
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (iter != app_info_data_.end()) {
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if ((*iter)->app_id() == app_id)
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return (*iter);
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++iter;
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NULL;
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const Notification ChromeNotifierService::CreateWelcomeNotificationForService(
794a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SyncedNotificationAppInfoTemp* app_info) {
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string welcome_notification_id = base::GenerateGUID();
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<WelcomeDelegate> delegate(new WelcomeDelegate(
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      welcome_notification_id, profile_, app_info->GetNotifierId()));
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_center::ButtonInfo button_info(
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  button_info.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IDR_NOTIFIER_BLOCK_BUTTON);
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_center::RichNotificationData rich_notification_data;
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  rich_notification_data.buttons.push_back(button_info);
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return Notification(
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::NOTIFICATION_TYPE_BASE_FORMAT,
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GURL(kSyncedNotificationsWelcomeOrigin),
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_info->title(),
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BODY),
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_info->icon(),
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blink::WebTextDirectionDefault,
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_info->GetNotifierId(),
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_DISPLAY_SOURCE),
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF8ToUTF16(welcome_notification_id),
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rich_notification_data,
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate.get());
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace notifier
821