chrome_notifier_service.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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"
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/notifications/sync_notifier/synced_notification_app_info.h"
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service.h"
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service_factory.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/notifications/sync_notifier/welcome_delegate.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
32d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/common/pref_names.h"
33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h"
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
36a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "grit/generated_resources.h"
37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "grit/theme_resources.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change.h"
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change_processor.h"
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_error_factory.h"
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/sync.pb.h"
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/synced_notification_specifics.pb.h"
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebTextDirection.h"
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/l10n/l10n_util.h"
45a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "ui/base/resource/resource_bundle.h"
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/message_center/notifier_settings.h"
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UserMetricsAction;
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace notifier {
52a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst char kFirstSyncedNotificationServiceId[] = "Google+";
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kSyncedNotificationsWelcomeOrigin[] =
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "synced-notifications://welcome";
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ChromeNotifierService::avoid_bitmap_fetching_for_test_ = false;
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::ChromeNotifierService(Profile* profile,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             NotificationUIManager* manager)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : profile_(profile),
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      notification_manager_(manager),
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      synced_notification_first_run_(false) {
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  InitializePrefs();
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Get a pointer to the app info service so we can get app info data.
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  synced_notification_app_info_service_ =
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      SyncedNotificationAppInfoServiceFactory::GetForProfile(
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          profile_, Profile::IMPLICIT_ACCESS);
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(synced_notification_app_info_service_ != NULL);
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  synced_notification_app_info_service_->set_chrome_notifier_service(this);
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
75a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
77effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochChromeNotifierService::~ChromeNotifierService() {
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (synced_notification_app_info_service_)
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    synced_notification_app_info_service_->set_chrome_notifier_service(NULL);
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Methods from KeyedService.
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChromeNotifierService::Shutdown() {}
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// syncer::SyncableService implementation.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is called at startup to sync with the server.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This code is not thread safe.
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type,
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncDataList& initial_sync_data,
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<syncer::SyncErrorFactory> error_handler) {
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  thread_checker_.CalledOnValidThread();
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A list of local changes to send up to the sync server.
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_ = sync_processor.Pass();
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != initial_sync_data.end(); ++it) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncData& sync_data = *it;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Build a local notification object from the sync data.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData(
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sync_data));
109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!incoming) {
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      NOTREACHED();
111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
112b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Process each incoming remote notification.
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key = incoming->GetKey();
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_GT(key.length(), 0U);
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SyncedNotification* found = FindNotificationById(key);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (NULL == found) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If there are no conflicts, copy in the data from remote.
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Add(incoming.Pass());
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the incoming (remote) and stored (local) notifications match
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // in all fields, we don't need to do anything here.
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (incoming->EqualsIgnoringReadState(*found)) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (incoming->GetReadState() == found->GetReadState()) {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Notification matches on the client and the server, nothing to do.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } else {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If the read state is different, read wins for both places.
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          if (incoming->GetReadState() == SyncedNotification::kDismissed) {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the server, but not the client.
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            found->NotificationHasBeenDismissed();
135ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // Tell the Notification UI Manager to remove it.
136ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            notification_manager_->CancelById(found->GetKey());
137ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          } else if (incoming->GetReadState() == SyncedNotification::kRead) {
138ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // If it is marked as read on the server, but not the client.
139ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            found->NotificationHasBeenRead();
140ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            // Tell the Notification UI Manager to remove it.
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            notification_manager_->CancelById(found->GetKey());
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the client, but not the server.
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer::SyncData sync_data = CreateSyncDataFromNotification(*found);
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            new_changes.push_back(
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                syncer::SyncChange(FROM_HERE,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   syncer::SyncChange::ACTION_UPDATE,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   sync_data));
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If local state changed, notify Notification UI Manager.
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // If different, just replace the local with the remote.
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(petewil): Someday we may allow changes from the client to
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // flow upwards, when we do, we will need better merge resolution.
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        found->Update(sync_data);
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        // Tell the notification manager to update the notification.
159ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(found);
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_changes.size() > 0) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    merge_result.set_error(sync_processor_->ProcessSyncChanges(
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, new_changes));
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Once we complete our first sync, we mark "first run" as false,
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // subsequent runs of Synced Notifications will get normal treatment.
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (synced_notification_first_run_) {
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    synced_notification_first_run_ = false;
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->SetBoolean(prefs::kSyncedNotificationFirstRun, false);
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return merge_result;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::StopSyncing(syncer::ModelType type) {
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Since this data type is not user-unselectable, we chose not to implement
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the stop syncing method, and instead do nothing here.
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncDataList ChromeNotifierService::GetAllSyncData(
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type) const {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncDataList sync_data;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy our native format data into a SyncDataList format.
192ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::const_iterator it =
193ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.begin();
194ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_data.push_back(CreateSyncDataFromNotification(**it));
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return sync_data;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This method is called when there is an incoming sync change from the server.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncError ChromeNotifierService::ProcessSyncChanges(
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const tracked_objects::Location& from_here,
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncChangeList& change_list) {
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  thread_checker_.CalledOnValidThread();
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncError error;
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncChangeList::const_iterator it = change_list.begin();
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != change_list.end(); ++it) {
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncData sync_data = it->sync_data();
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncChange::SyncChangeType change_type = it->change_type();
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> new_notification(
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        CreateNotificationFromSyncData(sync_data));
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!new_notification.get()) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Failed to read notification.";
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
221ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& key = new_notification->GetKey();
222ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    DCHECK_GT(key.length(), 0U);
223ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* found = FindNotificationById(key);
224ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (change_type) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case syncer::SyncChange::ACTION_ADD:
227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Intentional fall through, cases are identical.
228ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      case syncer::SyncChange::ACTION_UPDATE:
229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if (found == NULL) {
230ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          Add(new_notification.Pass());
231ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          break;
232ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        }
233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Update it in our store.
234ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        found->Update(sync_data);
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Tell the notification manager to update the notification.
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(found);
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        break;
238ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      case syncer::SyncChange::ACTION_DELETE:
240ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if (found == NULL) {
241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          break;
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        }
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Remove it from our store.
244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        FreeNotificationById(key);
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Remove it from the message center.
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        UpdateInMessageCenter(new_notification.get());
247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // TODO(petewil): Do I need to remember that it was deleted in case the
248ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // add arrives after the delete?  If so, how long do I need to remember?
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
252ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        NOTREACHED();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Support functions for data type conversion.
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static method.  Get to the sync data in our internal format.
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification(
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncedNotification& notification) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Construct the sync_data using the specifics from the notification.
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return syncer::SyncData::CreateLocalData(
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      notification.GetKey(), notification.GetKey(),
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      notification.GetEntitySpecifics());
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
271effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Convert from SyncData to our internal format.
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<SyncedNotification>
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ChromeNotifierService::CreateNotificationFromSyncData(
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncData& sync_data) {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get a pointer to our data within the sync_data object.
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_pb::SyncedNotificationSpecifics specifics =
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_data.GetSpecifics().synced_notification();
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for mandatory fields in the sync_data object.
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!specifics.has_coalesced_notification() ||
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !specifics.coalesced_notification().has_key() ||
282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !specifics.coalesced_notification().has_read_state()) {
283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification missing mandatory fields "
284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << "has coalesced notification? "
285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.has_coalesced_notification()
286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has key? " << specifics.coalesced_notification().has_key()
287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has read state? "
288b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.coalesced_notification().has_read_state();
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_unread_notification =
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kUnread &&
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       specifics.coalesced_notification().has_render_info());
297ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool is_well_formed_read_notification =
298ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      (static_cast<SyncedNotification::ReadState>(
299ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          specifics.coalesced_notification().read_state()) ==
300424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)       SyncedNotification::kRead);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_dismissed_notification =
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kDismissed);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the notification is poorly formed, return a null pointer.
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_well_formed_unread_notification &&
308ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      !is_well_formed_read_notification &&
309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !is_well_formed_dismissed_notification) {
310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification is not well formed."
311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " unread well formed? "
312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << is_well_formed_unread_notification
313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " dismissed well formed? "
314ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << is_well_formed_dismissed_notification
315ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << " read well formed? "
316ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch             << is_well_formed_read_notification;
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
318b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a new notification object based on the supplied sync_data.
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SyncedNotification> notification(
322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new SyncedNotification(sync_data, this, notification_manager_));
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return notification.Pass();
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This returns a pointer into a vector that we own.  Caller must not free it.
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns NULL if no match is found.
3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochSyncedNotification* ChromeNotifierService::FindNotificationById(
3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& notification_id) {
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): We can make a performance trade off here.
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // While the vector has good locality of reference, a map has faster lookup.
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Based on how big we expect this to get, maybe change this to a map.
334ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::const_iterator it =
335ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.begin();
336ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncedNotification* notification = *it;
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (notification_id == notification->GetKey())
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return *it;
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
345ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::FreeNotificationById(
346ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& notification_id) {
347ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ScopedVector<SyncedNotification>::iterator it = notification_data_.begin();
348ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (; it != notification_data_.end(); ++it) {
349ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* notification = *it;
350ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (notification_id == notification->GetKey()) {
351ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      notification_data_.erase(it);
352ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return;
353ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
354ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
355ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
356ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ChromeNotifierService::GetSyncedNotificationServices(
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::vector<message_center::Notifier*>* notifiers) {
3597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(mukai|petewil): Check the profile's eligibility before adding the
3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // sample app.
361effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<SyncedNotificationSendingServiceSettingsData>
362effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      sending_service_settings_data;
363effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
364effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (synced_notification_app_info_service_ == NULL)
365effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
367effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  sending_service_settings_data =
368effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      synced_notification_app_info_service_->GetAllSendingServiceSettingsData();
369effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
370effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (size_t ii = 0; ii < sending_service_settings_data.size(); ++ii) {
371effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
372effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Enable or disable the sending service per saved preferences.
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool app_enabled = false;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::set<std::string>::iterator iter;
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    iter = find(enabled_sending_services_.begin(),
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                enabled_sending_services_.end(),
377effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                sending_service_settings_data[ii].notifier_id.id);
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_enabled = iter != enabled_sending_services_.end();
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_center::Notifier* app_info_notifier = new message_center::Notifier(
381effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        sending_service_settings_data[ii].notifier_id,
382effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::UTF8ToUTF16(
383effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            sending_service_settings_data[ii].settings_display_name),
384effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        app_enabled);
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
386effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    app_info_notifier->icon = sending_service_settings_data[ii].settings_icon;
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // |notifiers| takes ownership of |app_info_notifier|.
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    notifiers->push_back(app_info_notifier);
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
393effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ChromeNotifierService::OnAddedAppIds(
394effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::vector<std::string> added_app_ids) {
395effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
396effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<std::string>::const_iterator app_id_iter;
397effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (app_id_iter = added_app_ids.begin(); app_id_iter != added_app_ids.end();
398effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++app_id_iter) {
399effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Make sure this is not a dup, if it is, do nothing.
400effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // TODO(petewil): consider a case insensitive compare.
401effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::set<std::string>::iterator sending_service_iter;
402effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    sending_service_iter = enabled_sending_services_.find(*app_id_iter);
403effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (sending_service_iter != enabled_sending_services_.end())
404effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      continue;
405effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
406effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Find any newly enabled notifications and call display on them.
407effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Show the welcome toast if required.
408effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ScopedVector<SyncedNotification>::iterator notification_iter;
409effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (notification_iter = notification_data_.begin();
410effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         notification_iter != notification_data_.end();
411effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++notification_iter) {
412effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      (*notification_iter)->ShowAllForAppId(profile_, *app_id_iter);
413effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
414effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
415effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
416effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
417effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ChromeNotifierService::OnRemovedAppIds(
418effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::vector<std::string> removed_app_ids) {
419effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Remove from enabled sending services.
420effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Don't remove from initialized sending services. If it gets re-added later,
421effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // we want to remember the user's decision, so we also leave prefs intact.
422effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
423effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Find any displayed notifications and remove them from the notification
424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // center.
425effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<std::string>::const_iterator app_id_iter;
426effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (app_id_iter = removed_app_ids.begin();
427effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       app_id_iter != removed_app_ids.end();
428effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++app_id_iter) {
429effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Find any newly disabled notifications and remove them.
430effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ScopedVector<SyncedNotification>::iterator notification_iter;
431effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (notification_iter = notification_data_.begin();
432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         notification_iter != notification_data_.end();
433effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++notification_iter) {
434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      (*notification_iter)->HideAllForAppId(*app_id_iter);
435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
437effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
438effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
439ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::MarkNotificationAsRead(
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key) {
441a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
4427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  SyncedNotification* notification = FindNotificationById(key);
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(notification != NULL);
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
445ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification->NotificationHasBeenRead();
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  new_changes.push_back(
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::SyncChange(FROM_HERE,
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         syncer::SyncChange::ACTION_UPDATE,
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         sync_data));
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Add a new notification to our data structure.  This takes ownership
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the passed in pointer.
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncedNotification* notification_copy = notification.get();
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Take ownership of the object and put it into our local storage.
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification_data_.push_back(notification.release());
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // If the user is not interested in this type of notification, ignore it.
466effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string sending_service_id = GetSendingServiceId(notification_copy);
467effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::set<std::string>::iterator iter = find(enabled_sending_services_.begin(),
468effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                              enabled_sending_services_.end(),
469effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                              sending_service_id);
470a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (iter == enabled_sending_services_.end()) {
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    iter = find(initialized_sending_services_.begin(),
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                initialized_sending_services_.end(),
473effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                sending_service_id);
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (iter != initialized_sending_services_.end())
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
476a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
477a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
478ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  UpdateInMessageCenter(notification_copy);
4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
481effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string ChromeNotifierService::GetSendingServiceId(
482effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const SyncedNotification* synced_notification) {
483effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Get the App Id from the notification, and look it up in the synced
484effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // notification app info service.
485effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string app_id = synced_notification->GetAppId();
486effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
487effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(synced_notification_app_info_service_ != NULL);
488effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
489effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return synced_notification_app_info_service_->FindSendingServiceNameFromAppId(
490effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      app_id);
491effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
492effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
4937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ChromeNotifierService::AddForTest(
4947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scoped_ptr<notifier::SyncedNotification> notification) {
495ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification_data_.push_back(notification.release());
496ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
4977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
498effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ChromeNotifierService::SetSyncedNotificationAppInfoServiceForTest(
499effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    SyncedNotificationAppInfoService* synced_notification_app_info_service) {
500effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If there already is a service attached, clear their reference to us.
501effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (synced_notification_app_info_service_)
502effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    synced_notification_app_info_service_->set_chrome_notifier_service(NULL);
503effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
504effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  synced_notification_app_info_service_ = synced_notification_app_info_service;
505effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  synced_notification_app_info_service_->set_chrome_notifier_service(this);
506effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
507effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
508ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::UpdateInMessageCenter(
509ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    SyncedNotification* notification) {
5102385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  // If the feature is disabled, exit now.
5112385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  if (!notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
512ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      CommandLine::ForCurrentProcess()))
5132385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return;
514a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
515ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  notification->LogNotification();
516ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
517ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (notification->GetReadState() == SyncedNotification::kUnread) {
518ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the message is unread, update it.
519ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    Display(notification);
520ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  } else {
521ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the message is read or deleted, dismiss it from the center.
522ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // We intentionally ignore errors if it is not in the center.
523ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    notification_manager_->CancelById(notification->GetKey());
524ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
525ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
526ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
527ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ChromeNotifierService::Display(SyncedNotification* notification) {
5284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If this is the first run for the feature, don't surprise the user.
5294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Instead, place all backlogged notifications into the notification
5304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // center.
5314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (synced_notification_first_run_) {
5324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Setting the toast state to false will prevent toasting the notification.
533effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    notification->set_toast_state(false);
5344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Our tests cannot use the network for reliability reasons.
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (avoid_bitmap_fetching_for_test_) {
538effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    notification->Show(profile_);
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Set up to fetch the bitmaps.
543effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  notification->QueueBitmapFetchJobs(this, profile_);
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Start the bitmap fetching, Show() will be called when the last bitmap
546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // either arrives or times out.
5477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  notification->StartBitmapFetch();
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ChromeNotifierService::OnSyncedNotificationServiceEnabled(
551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& notifier_id, bool enabled) {
552d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
553d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
554d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Make a copy of the notifier_id, which might not have lifetime long enough
555d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // for this function to finish all of its work.
556d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string notifier_id_copy(notifier_id);
557a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
558a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  iter = find(enabled_sending_services_.begin(),
559a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch              enabled_sending_services_.end(),
560d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              notifier_id_copy);
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue synced_notification_services;
563a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
564a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Add the notifier_id if it is enabled and not already there.
565a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (iter == enabled_sending_services_.end() && enabled) {
566d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    enabled_sending_services_.insert(notifier_id_copy);
5673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Check now for any outstanding notifications.
5683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DisplayUnreadNotificationsFromSource(notifier_id);
569d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    BuildServiceListValueInplace(enabled_sending_services_,
570d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 &synced_notification_services);
571d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Add this preference to the enabled list.
5724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
5734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              synced_notification_services);
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Remove the notifier_id if it is disabled and present.
575a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  } else if (iter != enabled_sending_services_.end() && !enabled) {
576a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    enabled_sending_services_.erase(iter);
577d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    BuildServiceListValueInplace(enabled_sending_services_,
578d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                 &synced_notification_services);
579d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Remove this peference from the enabled list.
5804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
5814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              synced_notification_services);
582d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    RemoveUnreadNotificationsFromSource(notifier_id_copy);
583a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
584a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
5858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Collect UMA statistics when a service is enabled or disabled.
5868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (enabled) {
5878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::RecordAction(
5888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        UserMetricsAction("SyncedNotifications.SendingServiceEnabled"));
5898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } else {
5908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::RecordAction(
5918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        UserMetricsAction("SyncedNotifications.SendingServiceDisabled"));
5928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
5938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Collect individual service enabling/disabling statistics.
5958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CollectPerServiceEnablingStatistics(notifier_id, enabled);
5968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
597a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return;
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
599eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
6008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ChromeNotifierService::CollectPerServiceEnablingStatistics(
6018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::string& notifier_id,
6028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool enabled) {
6038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(petewil) - This approach does not scale well as we add new services,
6048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // but we are limited to using predefined ENUM values in histogram based UMA
6058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // data, which does not permit arbitrary strings.
6068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Find a way to make it scale, or remove enum value this when we have enough
6078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // data.
6088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
6098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ChromeNotifierServiceActionType action =
6108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN;
6118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
6128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Derive action type from notifier_id and enabled.
6138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(petewil): Add more sending services as they are enabled.
6148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (notifier_id == std::string(kFirstSyncedNotificationServiceId)) {
6158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    action = enabled
6168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        ? CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED
6178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        : CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED;
6188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
6198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
6208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("ChromeNotifierService.Actions",
6218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            action,
6228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            CHROME_NOTIFIER_SERVICE_ACTION_COUNT);
6238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
6248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
625d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::BuildServiceListValueInplace(
6264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::set<std::string> services, base::ListValue* list_value) {
627d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
628d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
629d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Iterate over the strings, adding each one to the list value
630d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (iter = services.begin();
631d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       iter != services.end();
632d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       ++iter) {
6334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::StringValue* string_value(new base::StringValue(*iter));
6344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    list_value->Append(string_value);
635d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeNotifierService::DisplayUnreadNotificationsFromSource(
639d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& notifier_id) {
6403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator iter =
6413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          notification_data_.begin();
6423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != notification_data_.end();
6433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter) {
644effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (GetSendingServiceId(*iter) == notifier_id &&
6453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        (*iter)->GetReadState() == SyncedNotification::kUnread)
6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Display(*iter);
6473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
6483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeNotifierService::RemoveUnreadNotificationsFromSource(
651d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& notifier_id) {
6523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator iter =
6533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          notification_data_.begin();
6543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != notification_data_.end();
6553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter) {
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (GetSendingServiceId(*iter) == notifier_id &&
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        (*iter)->GetReadState() == SyncedNotification::kUnread) {
6583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      notification_manager_->CancelById((*iter)->GetKey());
659d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
6603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
6613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
663d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::OnEnabledSendingServiceListPrefChanged(
664d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::set<std::string>* ids_field) {
665d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ids_field->clear();
666d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::vector<std::string> pref_list =
667d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      enabled_sending_services_prefs_.GetValue();
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (size_t i = 0; i < pref_list.size(); ++i) {
669d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string element = pref_list[i];
670d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!element.empty())
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ids_field->insert(element);
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(WARNING) << i << "-th element is not a string "
674d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   << prefs::kEnabledSyncedNotificationSendingServices;
675d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
676d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
677d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
678d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::OnInitializedSendingServiceListPrefChanged(
679d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::set<std::string>* ids_field) {
680d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ids_field->clear();
681d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::vector<std::string> pref_list =
682d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      initialized_sending_services_prefs_.GetValue();
683d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (size_t i = 0; i < pref_list.size(); ++i) {
684d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string element = pref_list[i];
685d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!element.empty())
686d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ids_field->insert(element);
687d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
688d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      LOG(WARNING) << i << "-th element is not a string for "
689d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   << prefs::kInitializedSyncedNotificationSendingServices;
690d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
691d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
692d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ChromeNotifierService::OnSyncedNotificationFirstRunBooleanPrefChanged(
6944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    bool* new_value) {
6954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_ = *new_value;
6964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
698d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::RegisterProfilePrefs(
699d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
700d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Register the pref for the list of enabled services.
701d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  registry->RegisterListPref(
702d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
704d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Register the pref for the list of initialized services.
705d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  registry->RegisterListPref(
706d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
7084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Register the preference for first run status, defaults to "true",
7094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // meaning that this is the first run of the Synced Notification feature.
7104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registry->RegisterBooleanPref(
7114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kSyncedNotificationFirstRun, true,
7124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
713d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
714d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
715d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeNotifierService::InitializePrefs() {
716d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Set up any pref changes to update our list of services.
717d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  enabled_sending_services_prefs_.Init(
718d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kEnabledSyncedNotificationSendingServices,
719d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_->GetPrefs(),
720d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(
721d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &ChromeNotifierService::OnEnabledSendingServiceListPrefChanged,
722d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(this),
723d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(&enabled_sending_services_)));
724d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  initialized_sending_services_prefs_.Init(
725d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
726d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_->GetPrefs(),
727d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(
728d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &ChromeNotifierService::OnInitializedSendingServiceListPrefChanged,
729d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(this),
730d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          base::Unretained(&initialized_sending_services_)));
7314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_prefs_.Init(
7324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kSyncedNotificationFirstRun,
7334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_->GetPrefs(),
7344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(
7354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          &ChromeNotifierService::
7364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              OnSyncedNotificationFirstRunBooleanPrefChanged,
7374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          base::Unretained(this),
7384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          base::Unretained(&synced_notification_first_run_)));
739d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
740d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Get the prefs from last session into our memeber varilables
741d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  OnEnabledSendingServiceListPrefChanged(&enabled_sending_services_);
742d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  OnInitializedSendingServiceListPrefChanged(&initialized_sending_services_);
7438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
7444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  synced_notification_first_run_ =
7454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_->GetPrefs()->GetBoolean(prefs::kSyncedNotificationFirstRun);
746d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
747d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeNotifierService::ShowWelcomeToastIfNecessary(
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const SyncedNotification* synced_notification,
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NotificationUIManager* notification_ui_manager) {
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& sending_service_id =
752effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GetSendingServiceId(synced_notification);
753d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
754d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<std::string>::iterator iter;
755d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  iter = find(initialized_sending_services_.begin(),
756d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              initialized_sending_services_.end(),
7575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              sending_service_id);
7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If we already initialized the sending service, then return early since no
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // welcome toast is necessary.
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (iter != initialized_sending_services_.end())
762d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
763d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
764effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If there is no app info, we can't show a welcome toast.  All synced
7655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // notifications will be delayed until an app_info data structure can be
7665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // constructed for them.
767effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  notifier::SyncedNotificationAppInfo* app_info =
768effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FindAppInfoByAppId(synced_notification->GetAppId());
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!app_info)
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
772effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (app_info->settings_icon_url().is_empty()) {
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Image notification_app_icon = synced_notification->GetAppIcon();
774effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (notification_app_icon.IsEmpty()) {
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // This block should only be reached in tests since the downloads are
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // already finished for |synced_notification|.
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "Unable to find the app icon for the welcome notification. "
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << "Service ID: " << sending_service_id;
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_center::NotifierId notifier_id(
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::NotifierId::SYNCED_NOTIFICATION_SERVICE,
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sending_service_id);
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Notification notification = CreateWelcomeNotificationForService(app_info);
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  notification_ui_manager->Add(notification, profile_);
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enabled_sending_services_.insert(sending_service_id);
7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  initialized_sending_services_.insert(sending_service_id);
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
792d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Build a ListValue with the list of services to be enabled.
7934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue enabled_sending_services;
7944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue initialized_sending_services;
795d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
796d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Mark any new services as enabled in preferences.
7974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BuildServiceListValueInplace(enabled_sending_services_,
7984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               &enabled_sending_services);
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  profile_->GetPrefs()->Set(prefs::kEnabledSyncedNotificationSendingServices,
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            enabled_sending_services);
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Mark any new services as initialized in preferences.
8024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BuildServiceListValueInplace(initialized_sending_services_,
8034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               &initialized_sending_services);
8044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_->GetPrefs()->Set(
8054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      prefs::kInitializedSyncedNotificationSendingServices,
8064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      initialized_sending_services);
807d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
8083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
809effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnotifier::SyncedNotificationAppInfo* ChromeNotifierService::FindAppInfoByAppId(
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id) const {
811effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (NULL == synced_notification_app_info_service_)
812effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return NULL;
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
814effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return synced_notification_app_info_service_->
815effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FindSyncedNotificationAppInfoByAppId(app_id);
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const Notification ChromeNotifierService::CreateWelcomeNotificationForService(
819effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    SyncedNotificationAppInfo* app_info) {
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string welcome_notification_id = base::GenerateGUID();
821effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  message_center::NotifierId notifier_id = app_info->GetNotifierId();
822effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_refptr<WelcomeDelegate> delegate(
823effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new WelcomeDelegate(welcome_notification_id, profile_, notifier_id));
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_center::ButtonInfo button_info(
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  button_info.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IDR_NOTIFIER_BLOCK_BUTTON);
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_center::RichNotificationData rich_notification_data;
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  rich_notification_data.buttons.push_back(button_info);
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return Notification(
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::NOTIFICATION_TYPE_BASE_FORMAT,
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GURL(kSyncedNotificationsWelcomeOrigin),
835effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::UTF8ToUTF16(app_info->settings_display_name()),
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BODY),
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_info->icon(),
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blink::WebTextDirectionDefault,
839effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      notifier_id,
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_DISPLAY_SOURCE),
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF8ToUTF16(welcome_notification_id),
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rich_notification_data,
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate.get());
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace notifier
847