Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |