chrome_notifier_service.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification_ui_manager.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "googleurl/src/gurl.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change_processor.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_error_factory.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/sync.pb.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/synced_notification_specifics.pb.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace notifier {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ChromeNotifierService::avoid_bitmap_fetching_for_test_ = false;
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::ChromeNotifierService(Profile* profile,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             NotificationUIManager* manager)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile), notification_manager_(manager) {}
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::~ChromeNotifierService() {}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Methods from BrowserContextKeyedService.
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChromeNotifierService::Shutdown() {}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// syncer::SyncableService implementation.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is called at startup to sync with the server.
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This code is not thread safe.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::ModelType type,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const syncer::SyncDataList& initial_sync_data,
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<syncer::SyncErrorFactory> error_handler) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): After I add the infrastructure for the test, add a check
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that we are currently on the UI thread here.
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS);
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A list of local changes to send up to the sync server.
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_ = sync_processor.Pass();
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != initial_sync_data.end(); ++it) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncData& sync_data = *it;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Build a local notification object from the sync data.
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData(
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sync_data));
59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!incoming) {
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // TODO(petewil): Turn this into a NOTREACHED() call once we fix the
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // underlying problem causing bad data.
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      LOG(WARNING) << "Badly formed sync data in incoming notification";
63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Process each incoming remote notification.
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key = incoming->GetKey();
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_GT(key.length(), 0U);
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SyncedNotification* found = FindNotificationByKey(key);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (NULL == found) {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If there are no conflicts, copy in the data from remote.
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Add(incoming.Pass());
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the incoming (remote) and stored (local) notifications match
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // in all fields, we don't need to do anything here.
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (incoming->EqualsIgnoringReadState(*found)) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (incoming->GetReadState() == found->GetReadState()) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Notification matches on the client and the server, nothing to do.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } else  {
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If the read state is different, read wins for both places.
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          if (incoming->GetReadState() == SyncedNotification::kDismissed) {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the server, but not the client.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            found->NotificationHasBeenDismissed();
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // TODO(petewil): Tell the Notification UI Manager to mark it read.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is marked as read on the client, but not the server.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer::SyncData sync_data = CreateSyncDataFromNotification(*found);
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            new_changes.push_back(
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                syncer::SyncChange(FROM_HERE,
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   syncer::SyncChange::ACTION_UPDATE,
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   sync_data));
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If local state changed, notify Notification UI Manager.
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // For any other conflict besides read state, treat it as an update.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // If different, just replace the local with the remote.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(petewil): Someday we may allow changes from the client to
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // flow upwards, when we do, we will need better merge resolution.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        found->Update(sync_data);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_changes.size() > 0) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    merge_result.set_error(sync_processor_->ProcessSyncChanges(
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, new_changes));
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return merge_result;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::StopSyncing(syncer::ModelType type) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): implement
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncDataList ChromeNotifierService::GetAllSyncData(
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::ModelType type) const {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncDataList sync_data;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Copy our native format data into a SyncDataList format.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator it =
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          notification_data_.begin();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      it != notification_data_.end();
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++it) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_data.push_back(CreateSyncDataFromNotification(**it));
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return sync_data;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This method is called when there is an incoming sync change from the server.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncError ChromeNotifierService::ProcessSyncChanges(
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const tracked_objects::Location& from_here,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const syncer::SyncChangeList& change_list) {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): add a check that we are called on the thread we expect.
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncError error;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (syncer::SyncChangeList::const_iterator it = change_list.begin();
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != change_list.end(); ++it) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncData sync_data = it->sync_data();
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncChange::SyncChangeType change_type = it->change_type();
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<SyncedNotification> new_notification(
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        CreateNotificationFromSyncData(sync_data));
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!new_notification.get()) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Failed to read notification.";
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (change_type) {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case syncer::SyncChange::ACTION_ADD:
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(petewil): Update the notification if it already exists
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // as opposed to adding it.
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Add(new_notification.Pass());
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(petewil): Implement code to add delete and update actions.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error;
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Support functions for data type conversion.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static method.  Get to the sync data in our internal format.
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification(
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncedNotification& notification) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Construct the sync_data using the specifics from the notification.
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return syncer::SyncData::CreateLocalData(
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      notification.GetKey(), notification.GetKey(),
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      notification.GetEntitySpecifics());
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static Method.  Convert from SyncData to our internal format.
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<SyncedNotification>
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ChromeNotifierService::CreateNotificationFromSyncData(
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const syncer::SyncData& sync_data) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get a pointer to our data within the sync_data object.
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_pb::SyncedNotificationSpecifics specifics =
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_data.GetSpecifics().synced_notification();
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for mandatory fields in the sync_data object.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!specifics.has_coalesced_notification() ||
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !specifics.coalesced_notification().has_key() ||
196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !specifics.coalesced_notification().has_read_state()) {
197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification missing mandatory fields "
198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << "has coalesced notification? "
199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.has_coalesced_notification()
200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has key? " << specifics.coalesced_notification().has_key()
201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " has read state? "
202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << specifics.coalesced_notification().has_read_state();
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): Is this the right set?  Should I add more?
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_unread_notification =
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kUnread &&
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       specifics.coalesced_notification().has_render_info());
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_well_formed_dismissed_notification =
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (static_cast<SyncedNotification::ReadState>(
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          specifics.coalesced_notification().read_state()) ==
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       SyncedNotification::kDismissed);
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // if the notification is poorly formed, return a null pointer
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_well_formed_unread_notification &&
219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !is_well_formed_dismissed_notification) {
220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DVLOG(1) << "Synced Notification is not well formed."
221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " unread well formed? "
222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << is_well_formed_unread_notification
223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << " dismissed well formed? "
224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             << is_well_formed_dismissed_notification;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<SyncedNotification>();
226b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a new notification object based on the supplied sync_data.
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SyncedNotification> notification(
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new SyncedNotification(sync_data));
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return notification.Pass();
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This returns a pointer into a vector that we own.  Caller must not free it.
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns NULL if no match is found.
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SyncedNotification* ChromeNotifierService::FindNotificationByKey(
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key) {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(petewil): We can make a performance trade off here.
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // While the vector has good locality of reference, a map has faster lookup.
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Based on how big we expect this to get, maybe change this to a map.
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<SyncedNotification*>::const_iterator it =
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          notification_data_.begin();
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      it != notification_data_.end();
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++it) {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncedNotification* notification = *it;
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (key == notification->GetKey())
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return *it;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ChromeNotifierService::MarkNotificationAsDismissed(
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key) {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SyncedNotification* notification = FindNotificationByKey(key);
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(notification != NULL);
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification->NotificationHasBeenDismissed();
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncChangeList new_changes;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  new_changes.push_back(
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::SyncChange(FROM_HERE,
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         syncer::SyncChange::ACTION_UPDATE,
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         sync_data));
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send up the changes that were made locally.
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Add a new notification to our data structure.  This takes ownership
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the passed in pointer.
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncedNotification* notification_copy = notification.get();
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Take ownership of the object and put it into our local storage.
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification_data_.push_back(notification.release());
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set up to fetch the bitmaps.
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  notification_copy->QueueBitmapFetchJobs(notification_manager_,
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          this,
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          profile_);
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Our tests cannot use the network for reliability reasons.
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (avoid_bitmap_fetching_for_test_) {
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Start the bitmap fetching, Show() will be called when the last bitmap
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // either arrives or times out.
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  notification_copy->StartBitmapFetch();
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace notifier
295