chrome_notifier_service.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 "base/utf_string_conversions.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/browser_process.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/notification_ui_manager.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "googleurl/src/gurl.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_change_processor.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_error_factory.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/sync.pb.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/protocol/synced_notification_specifics.pb.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace notifier { 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::ChromeNotifierService(Profile* profile, 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationUIManager* manager) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : profile_(profile), notification_manager_(manager) {} 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeNotifierService::~ChromeNotifierService() {} 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Methods from ProfileKeyedService. 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Shutdown() { 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// syncer::SyncableService implementation. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is called at startup to sync with the server. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This code is not thread safe. 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing( 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::ModelType type, 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const syncer::SyncDataList& initial_sync_data, 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<syncer::SyncErrorFactory> error_handler) { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): After I add the infrastructure for the test, add a check 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // that we are currently on the UI thread here. 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A list of local changes to send up to the sync server. 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChangeList new_changes; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_processor_ = sync_processor.Pass(); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != initial_sync_data.end(); ++it) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const syncer::SyncData& sync_data = *it; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType()); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Build a local notification object from the sync data. 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData( 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_data)); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(incoming.get()); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Process each incoming remote notification. 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& id = incoming->notification_id(); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GT(id.length(), 0U); 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification* found = FindNotificationById(id); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (NULL == found) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If there are no conflicts, copy in the data from remote. 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Add(incoming.Pass()); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the incoming (remote) and stored (local) notifications match 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in all fields, we don't need to do anything here. 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming->EqualsIgnoringReadState(*found)) { 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming->read_state() == found->read_state()) { 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Notification matches on the client and the server, nothing to do. 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the read state is different, read wins for both places. 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming->read_state() == SyncedNotification::kDismissed) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If it is marked as read on the server, but not the client. 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) found->NotificationHasBeenDismissed(); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): Tell the Notification UI Manager to mark it read. 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If it is marked as read on the client, but not the server. 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncData sync_data = CreateSyncDataFromNotification(*found); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new_changes.push_back( 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChange(FROM_HERE, 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChange::ACTION_UPDATE, 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_data)); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If local state changed, notify Notification UI Manager. 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // For any other conflict besides read state, treat it as an update. 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If different, just replace the local with the remote. 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): Someday we may allow changes from the client to 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // flow upwards, when we do, we will need better merge resolution. 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) found->Update(sync_data); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Send up the changes that were made locally. 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (new_changes.size() > 0) { 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) merge_result.set_error(sync_processor_->ProcessSyncChanges( 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, new_changes)); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return merge_result; 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::StopSyncing(syncer::ModelType type) { 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): implement 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncDataList ChromeNotifierService::GetAllSyncData( 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::ModelType type) const { 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, type); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncDataList sync_data; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Copy our native format data into a SyncDataList format. 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<SyncedNotification*>::const_iterator it = 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification_data_.begin(); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != notification_data_.end(); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it) { 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_data.push_back(CreateSyncDataFromNotification(**it)); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return sync_data; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This method is called when there is an incoming sync change from the server. 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncError ChromeNotifierService::ProcessSyncChanges( 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const tracked_objects::Location& from_here, 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const syncer::SyncChangeList& change_list) { 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): add a check that we are called on the thread we expect. 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncError error; 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (syncer::SyncChangeList::const_iterator it = change_list.begin(); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != change_list.end(); ++it) { 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncData sync_data = it->sync_data(); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType()); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChange::SyncChangeType change_type = it->change_type(); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<SyncedNotification> new_notification( 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreateNotificationFromSyncData(sync_data)); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!new_notification.get()) { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << "Failed to read notification."; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (change_type) { 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case syncer::SyncChange::ACTION_ADD: 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): Update the notification if it already exists 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // as opposed to adding it. 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Add(new_notification.Pass()); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): Implement code to add delete and update actions. 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return error; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Support functions for data type conversion. 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static method. Get to the sync data in our internal format. 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification( 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SyncedNotification& notification) { 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Construct the sync_data using the specifics from the notification. 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return syncer::SyncData::CreateLocalData( 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification.notification_id(), notification.notification_id(), 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification.GetEntitySpecifics()); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static Method. Convert from SyncData to our internal format. 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<SyncedNotification> 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChromeNotifierService::CreateNotificationFromSyncData( 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const syncer::SyncData& sync_data) { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get a pointer to our data within the sync_data object. 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_pb::SyncedNotificationSpecifics specifics = 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_data.GetSpecifics().synced_notification(); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check for mandatory fields in the sync_data object. 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!specifics.has_coalesced_notification() || 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !specifics.coalesced_notification().has_key() || 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !specifics.coalesced_notification().has_read_state()) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<SyncedNotification>(); 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): Is this the right set? Should I add more? 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_well_formed_unread_notification = 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (static_cast<SyncedNotification::ReadState>( 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) specifics.coalesced_notification().read_state()) == 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification::kUnread && 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) specifics.coalesced_notification().has_render_info()); 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_well_formed_dismissed_notification = 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (static_cast<SyncedNotification::ReadState>( 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) specifics.coalesced_notification().read_state()) == 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification::kDismissed); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // if the notification is poorly formed, return a null pointer 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_well_formed_unread_notification && 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !is_well_formed_dismissed_notification) 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<SyncedNotification>(); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create a new notification object based on the supplied sync_data. 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<SyncedNotification> notification( 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new SyncedNotification(sync_data)); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return notification.Pass(); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This returns a pointer into a vector that we own. Caller must not free it. 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns NULL if no match is found. 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This uses the <app_id/coalescing_key> pair as a key. 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncedNotification* ChromeNotifierService::FindNotificationById( 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& id) { 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): We can make a performance trade off here. 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // While the vector has good locality of reference, a map has faster lookup. 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Based on how big we expect this to get, maybe change this to a map. 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<SyncedNotification*>::const_iterator it = 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification_data_.begin(); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != notification_data_.end(); 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it) { 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification* notification = *it; 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (id == notification->notification_id()) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return *it; 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::MarkNotificationAsDismissed(const std::string& id) { 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification* notification = FindNotificationById(id); 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK(notification != NULL); 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification->NotificationHasBeenDismissed(); 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChangeList new_changes; 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification); 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new_changes.push_back( 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChange(FROM_HERE, 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncChange::ACTION_UPDATE, 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_data)); 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Send up the changes that were made locally. 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Add a new notification to our data structure. This takes ownership 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the passed in pointer. 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) { 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification* notification_copy = notification.get(); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Take ownership of the object and put it into our local storage. 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification_data_.push_back(notification.release()); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Show it to the user. 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Show(notification_copy); 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Send the notification to the NotificationUIManager to show to the user. 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeNotifierService::Show(SyncedNotification* notification) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Set up the fields we need to send and create a Notification object. 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL origin_url(notification->origin_url()); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL app_icon_url(notification->app_icon_url()); 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 title = UTF8ToUTF16(notification->title()); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 text = UTF8ToUTF16(notification->text()); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 heading = UTF8ToUTF16(notification->heading()); 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 description = UTF8ToUTF16(notification->description()); 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): What goes in the display source, is empty OK? 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 display_source; 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 replace_id = UTF8ToUTF16(notification->notification_id()); 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(petewil): For now, just punt on dismissed notifications until 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // I change the interface to let NotificationUIManager know the right way. 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SyncedNotification::kRead == notification->read_state() || 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SyncedNotification::kDismissed == notification->read_state() ) { 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(2) << "Not showing dismissed notification" 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << notification->title() << " " << notification->text(); 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The delegate will eventually catch calls that the notification 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // was read or deleted, and send the changes back to the server. 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<NotificationDelegate> delegate = 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new ChromeNotifierDelegate(notification->notification_id(), this); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Notification ui_notification(origin_url, app_icon_url, heading, description, 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebKit::WebTextDirectionDefault, 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) display_source, replace_id, delegate); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) notification_manager_->Add(ui_notification, profile_); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "Synced Notification arrived! " << title << " " << text 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << " " << app_icon_url << " " << replace_id << " " 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << notification->read_state(); 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace notifier 310