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 |