Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc

Issue 22470006: Process incoming updates and deletes properly. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // The ChromeNotifierService works together with sync to maintain the state of 5 // The ChromeNotifierService works together with sync to maintain the state of
6 // user notifications, which can then be presented in the notification center, 6 // user notifications, which can then be presented in the notification center,
7 // via the Notification UI Manager. 7 // via the Notification UI Manager.
8 8
9 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h" 9 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
10 10
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 // If local state changed, notify Notification UI Manager. 115 // If local state changed, notify Notification UI Manager.
116 } 116 }
117 // For any other conflict besides read state, treat it as an update. 117 // For any other conflict besides read state, treat it as an update.
118 } else { 118 } else {
119 // If different, just replace the local with the remote. 119 // If different, just replace the local with the remote.
120 // TODO(petewil): Someday we may allow changes from the client to 120 // TODO(petewil): Someday we may allow changes from the client to
121 // flow upwards, when we do, we will need better merge resolution. 121 // flow upwards, when we do, we will need better merge resolution.
122 found->Update(sync_data); 122 found->Update(sync_data);
123 123
124 // Tell the notification manager to update the notification. 124 // Tell the notification manager to update the notification.
125 Display(found); 125 UpdateInMessageCenter(found);
126 } 126 }
127 } 127 }
128 } 128 }
129 129
130 // Send up the changes that were made locally. 130 // Send up the changes that were made locally.
131 if (new_changes.size() > 0) { 131 if (new_changes.size() > 0) {
132 merge_result.set_error(sync_processor_->ProcessSyncChanges( 132 merge_result.set_error(sync_processor_->ProcessSyncChanges(
133 FROM_HERE, new_changes)); 133 FROM_HERE, new_changes));
134 } 134 }
135 135
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType()); 170 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
171 syncer::SyncChange::SyncChangeType change_type = it->change_type(); 171 syncer::SyncChange::SyncChangeType change_type = it->change_type();
172 172
173 scoped_ptr<SyncedNotification> new_notification( 173 scoped_ptr<SyncedNotification> new_notification(
174 CreateNotificationFromSyncData(sync_data)); 174 CreateNotificationFromSyncData(sync_data));
175 if (!new_notification.get()) { 175 if (!new_notification.get()) {
176 NOTREACHED() << "Failed to read notification."; 176 NOTREACHED() << "Failed to read notification.";
177 continue; 177 continue;
178 } 178 }
179 179
180 const std::string& key = new_notification->GetKey();
181 DCHECK_GT(key.length(), 0U);
182 SyncedNotification* found = FindNotificationById(key);
183
180 switch (change_type) { 184 switch (change_type) {
181 case syncer::SyncChange::ACTION_ADD: 185 case syncer::SyncChange::ACTION_ADD:
182 // TODO(petewil): Update the notification if it already exists 186 if (found != NULL) {
183 // as opposed to adding it. 187 found->Update(sync_data);
188 UpdateInMessageCenter(found);
189 break;
190 }
184 Add(new_notification.Pass()); 191 Add(new_notification.Pass());
185 break; 192 break;
186 // TODO(petewil): Implement code to add delete and update actions. 193
194 case syncer::SyncChange::ACTION_UPDATE:
195 if (found == NULL) {
dewittj 2013/08/08 22:15:32 Unless I understand the protocol wrong, this could
Pete Williamson 2013/08/09 01:27:22 This seems like a fairly rare race condition, it s
196 Add(new_notification.Pass());
197 break;
198 }
199 // Update it in our store.
200 found->Update(sync_data);
201 // Tell the notification manager to update the notification.
202 UpdateInMessageCenter(found);
203 break;
204
205 case syncer::SyncChange::ACTION_DELETE:
206 if (found == NULL) {
207 break;
208 }
209 // Remove it from our store.
210 FreeNotificationById(key);
211 // Remove it from the message center.
212 UpdateInMessageCenter(new_notification.get());
213 // TODO(petewil): Do I need to remember that it was deleted in case the
214 // add arrives after the delete? If so, how long do I need to remember?
215 break;
187 216
188 default: 217 default:
218 NOTREACHED();
189 break; 219 break;
190 } 220 }
191 } 221 }
192 222
193 return error; 223 return error;
194 } 224 }
195 225
196 // Support functions for data type conversion. 226 // Support functions for data type conversion.
197 227
198 // Static method. Get to the sync data in our internal format. 228 // Static method. Get to the sync data in our internal format.
(...skipping 18 matching lines...) Expand all
217 !specifics.coalesced_notification().has_key() || 247 !specifics.coalesced_notification().has_key() ||
218 !specifics.coalesced_notification().has_read_state()) { 248 !specifics.coalesced_notification().has_read_state()) {
219 DVLOG(1) << "Synced Notification missing mandatory fields " 249 DVLOG(1) << "Synced Notification missing mandatory fields "
220 << "has coalesced notification? " 250 << "has coalesced notification? "
221 << specifics.has_coalesced_notification() 251 << specifics.has_coalesced_notification()
222 << " has key? " << specifics.coalesced_notification().has_key() 252 << " has key? " << specifics.coalesced_notification().has_key()
223 << " has read state? " 253 << " has read state? "
224 << specifics.coalesced_notification().has_read_state(); 254 << specifics.coalesced_notification().has_read_state();
225 return scoped_ptr<SyncedNotification>(); 255 return scoped_ptr<SyncedNotification>();
226 } 256 }
227
228 // TODO(petewil): Is this the right set? Should I add more?
229 bool is_well_formed_unread_notification = 257 bool is_well_formed_unread_notification =
230 (static_cast<SyncedNotification::ReadState>( 258 (static_cast<SyncedNotification::ReadState>(
231 specifics.coalesced_notification().read_state()) == 259 specifics.coalesced_notification().read_state()) ==
232 SyncedNotification::kUnread && 260 SyncedNotification::kUnread &&
233 specifics.coalesced_notification().has_render_info()); 261 specifics.coalesced_notification().has_render_info());
262 bool is_well_formed_read_notification =
263 (static_cast<SyncedNotification::ReadState>(
264 specifics.coalesced_notification().read_state()) ==
265 SyncedNotification::kRead &&
266 specifics.coalesced_notification().has_render_info());
234 bool is_well_formed_dismissed_notification = 267 bool is_well_formed_dismissed_notification =
235 (static_cast<SyncedNotification::ReadState>( 268 (static_cast<SyncedNotification::ReadState>(
236 specifics.coalesced_notification().read_state()) == 269 specifics.coalesced_notification().read_state()) ==
237 SyncedNotification::kDismissed); 270 SyncedNotification::kDismissed);
238 271
239 // If the notification is poorly formed, return a null pointer. 272 // If the notification is poorly formed, return a null pointer.
240 if (!is_well_formed_unread_notification && 273 if (!is_well_formed_unread_notification &&
274 !is_well_formed_read_notification &&
241 !is_well_formed_dismissed_notification) { 275 !is_well_formed_dismissed_notification) {
242 DVLOG(1) << "Synced Notification is not well formed." 276 DVLOG(1) << "Synced Notification is not well formed."
243 << " unread well formed? " 277 << " unread well formed? "
244 << is_well_formed_unread_notification 278 << is_well_formed_unread_notification
245 << " dismissed well formed? " 279 << " dismissed well formed? "
246 << is_well_formed_dismissed_notification; 280 << is_well_formed_dismissed_notification
281 << " read well formed? "
282 << is_well_formed_read_notification;
247 return scoped_ptr<SyncedNotification>(); 283 return scoped_ptr<SyncedNotification>();
248 } 284 }
249 285
250 // Create a new notification object based on the supplied sync_data. 286 // Create a new notification object based on the supplied sync_data.
251 scoped_ptr<SyncedNotification> notification( 287 scoped_ptr<SyncedNotification> notification(
252 new SyncedNotification(sync_data)); 288 new SyncedNotification(sync_data));
253 289
254 return notification.Pass(); 290 return notification.Pass();
255 } 291 }
256 292
257 // This returns a pointer into a vector that we own. Caller must not free it. 293 // This returns a pointer into a vector that we own. Caller must not free it.
258 // Returns NULL if no match is found. 294 // Returns NULL if no match is found.
259 SyncedNotification* ChromeNotifierService::FindNotificationById( 295 SyncedNotification* ChromeNotifierService::FindNotificationById(
260 const std::string& notification_id) { 296 const std::string& notification_id) {
261 // TODO(petewil): We can make a performance trade off here. 297 // TODO(petewil): We can make a performance trade off here.
262 // While the vector has good locality of reference, a map has faster lookup. 298 // While the vector has good locality of reference, a map has faster lookup.
263 // Based on how big we expect this to get, maybe change this to a map. 299 // Based on how big we expect this to get, maybe change this to a map.
264 for (std::vector<SyncedNotification*>::const_iterator it = 300 for (std::vector<SyncedNotification*>::const_iterator it =
265 notification_data_.begin(); 301 notification_data_.begin();
266 it != notification_data_.end(); 302 it != notification_data_.end();
267 ++it) { 303 ++it) {
268 SyncedNotification* notification = *it; 304 SyncedNotification* notification = *it;
269 if (notification_id == notification->GetKey()) 305 if (notification_id == notification->GetKey())
270 return *it; 306 return *it;
271 } 307 }
272 308
273 return NULL; 309 return NULL;
274 } 310 }
275 311
312 void ChromeNotifierService::FreeNotificationById(
313 const std::string& notification_id) {
314 for (std::vector<SyncedNotification*>::iterator it =
315 notification_data_.begin();
316 it != notification_data_.end();
317 ++it) {
318 SyncedNotification* notification = *it;
319 if (notification_id == notification->GetKey()) {
320 notification_data_.erase(it);
321 return;
322 }
323 }
324 }
325
276 void ChromeNotifierService::GetSyncedNotificationServices( 326 void ChromeNotifierService::GetSyncedNotificationServices(
277 std::vector<message_center::Notifier*>* notifiers) { 327 std::vector<message_center::Notifier*>* notifiers) {
278 // TODO(mukai|petewil): Check the profile's eligibility before adding the 328 // TODO(mukai|petewil): Check the profile's eligibility before adding the
279 // sample app. 329 // sample app.
280 330
281 // TODO(petewil): Really obtain the list of synced notification sending 331 // TODO(petewil): Really obtain the list of synced notification sending
282 // services from the server and create the list of ids here. Until then, we 332 // services from the server and create the list of ids here. Until then, we
283 // are hardcoding the service names. Once that is done, remove this 333 // are hardcoding the service names. Once that is done, remove this
284 // hardcoding. 334 // hardcoding.
285 // crbug.com/248337 335 // crbug.com/248337
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 383
334 // If the user is not interested in this type of notification, ignore it. 384 // If the user is not interested in this type of notification, ignore it.
335 std::vector<std::string>::iterator iter = 385 std::vector<std::string>::iterator iter =
336 find(enabled_sending_services_.begin(), 386 find(enabled_sending_services_.begin(),
337 enabled_sending_services_.end(), 387 enabled_sending_services_.end(),
338 notification_copy->GetSendingServiceId()); 388 notification_copy->GetSendingServiceId());
339 if (iter == enabled_sending_services_.end()) { 389 if (iter == enabled_sending_services_.end()) {
340 return; 390 return;
341 } 391 }
342 392
343 Display(notification_copy); 393 UpdateInMessageCenter(notification_copy);
344 } 394 }
345 395
346 void ChromeNotifierService::AddForTest( 396 void ChromeNotifierService::AddForTest(
347 scoped_ptr<notifier::SyncedNotification> notification) { 397 scoped_ptr<notifier::SyncedNotification> notification) {
348 notification_data_.push_back(notification.release()); 398 notification_data_.push_back(notification.release());
349 } 399 }
350 400
351 void ChromeNotifierService::Display(SyncedNotification* notification) { 401 void ChromeNotifierService::UpdateInMessageCenter(
402 SyncedNotification* notification) {
352 // If the feature is disabled, exit now. 403 // If the feature is disabled, exit now.
353 if (!notifier::ChromeNotifierServiceFactory::UseSyncedNotifications( 404 if (!notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
354 CommandLine::ForCurrentProcess())) 405 CommandLine::ForCurrentProcess()))
355 return; 406 return;
356 407
408 if (notification->GetReadState() == SyncedNotification::kUnread) {
409 // If the message is unread, update it.
410 Display(notification);
411 } else {
412 // If the message is read or deleted, dismiss it from the center.
413 // We intentionally ignore errors if it is not in the center.
414 notification_manager_->CancelById(notification->GetKey());
415 }
416 }
417
418 void ChromeNotifierService::Display(SyncedNotification* notification) {
357 // Set up to fetch the bitmaps. 419 // Set up to fetch the bitmaps.
358 notification->QueueBitmapFetchJobs(notification_manager_, 420 notification->QueueBitmapFetchJobs(notification_manager_,
359 this, 421 this,
360 profile_); 422 profile_);
361 423
362 // Our tests cannot use the network for reliability reasons. 424 // Our tests cannot use the network for reliability reasons.
363 if (avoid_bitmap_fetching_for_test_) { 425 if (avoid_bitmap_fetching_for_test_) {
364 return; 426 return;
365 } 427 }
366 428
(...skipping 17 matching lines...) Expand all
384 // Remove the notifier_id if it is disabled and present. 446 // Remove the notifier_id if it is disabled and present.
385 } else if (iter != enabled_sending_services_.end() && !enabled) { 447 } else if (iter != enabled_sending_services_.end() && !enabled) {
386 enabled_sending_services_.erase(iter); 448 enabled_sending_services_.erase(iter);
387 } 449 }
388 450
389 // Otherwise, nothing to do, we can exit. 451 // Otherwise, nothing to do, we can exit.
390 return; 452 return;
391 } 453 }
392 454
393 } // namespace notifier 455 } // namespace notifier
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698