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

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

Issue 12717010: Widen Data Pipes and newer protobufs (Closed) Base URL: http://git.chromium.org/chromium/src.git@newProtobufs
Patch Set: Synced Notifications newer protobufs - fix mac and linux unit tests Created 7 years, 8 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
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
11 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/notifications/notification.h" 13 #include "chrome/browser/notifications/notification.h"
14 #include "chrome/browser/notifications/notification_ui_manager.h" 14 #include "chrome/browser/notifications/notification_ui_manager.h"
15 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h" 15 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h"
16 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
17 #include "googleurl/src/gurl.h" 17 #include "googleurl/src/gurl.h"
18 #include "sync/api/sync_change.h" 18 #include "sync/api/sync_change.h"
19 #include "sync/api/sync_change_processor.h" 19 #include "sync/api/sync_change_processor.h"
20 #include "sync/api/sync_error_factory.h" 20 #include "sync/api/sync_error_factory.h"
21 #include "sync/protocol/sync.pb.h" 21 #include "sync/protocol/sync.pb.h"
22 #include "sync/protocol/synced_notification_specifics.pb.h" 22 #include "sync/protocol/synced_notification_specifics.pb.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h"
24 #include "ui/message_center/notification_types.h"
24 25
25 namespace notifier { 26 namespace notifier {
26 27
27 ChromeNotifierService::ChromeNotifierService(Profile* profile, 28 ChromeNotifierService::ChromeNotifierService(Profile* profile,
28 NotificationUIManager* manager) 29 NotificationUIManager* manager)
29 : profile_(profile), notification_manager_(manager) {} 30 : profile_(profile), notification_manager_(manager) {}
30 ChromeNotifierService::~ChromeNotifierService() {} 31 ChromeNotifierService::~ChromeNotifierService() {}
31 32
32 // Methods from ProfileKeyedService. 33 // Methods from ProfileKeyedService.
33 void ChromeNotifierService::Shutdown() { 34 void ChromeNotifierService::Shutdown() {
(...skipping 20 matching lines...) Expand all
54 it != initial_sync_data.end(); ++it) { 55 it != initial_sync_data.end(); ++it) {
55 const syncer::SyncData& sync_data = *it; 56 const syncer::SyncData& sync_data = *it;
56 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType()); 57 DCHECK_EQ(syncer::SYNCED_NOTIFICATIONS, sync_data.GetDataType());
57 58
58 // Build a local notification object from the sync data. 59 // Build a local notification object from the sync data.
59 scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData( 60 scoped_ptr<SyncedNotification> incoming(CreateNotificationFromSyncData(
60 sync_data)); 61 sync_data));
61 DCHECK(incoming.get()); 62 DCHECK(incoming.get());
62 63
63 // Process each incoming remote notification. 64 // Process each incoming remote notification.
64 const std::string& id = incoming->notification_id(); 65 const std::string& key = incoming->GetKey();
65 DCHECK_GT(id.length(), 0U); 66 DCHECK_GT(key.length(), 0U);
66 SyncedNotification* found = FindNotificationById(id); 67 SyncedNotification* found = FindNotificationByKey(key);
67 68
68 if (NULL == found) { 69 if (NULL == found) {
69 // If there are no conflicts, copy in the data from remote. 70 // If there are no conflicts, copy in the data from remote.
70 Add(incoming.Pass()); 71 Add(incoming.Pass());
71 } else { 72 } else {
72 // If the incoming (remote) and stored (local) notifications match 73 // If the incoming (remote) and stored (local) notifications match
73 // in all fields, we don't need to do anything here. 74 // in all fields, we don't need to do anything here.
74 if (incoming->EqualsIgnoringReadState(*found)) { 75 if (incoming->EqualsIgnoringReadState(*found)) {
75 76
76 if (incoming->read_state() == found->read_state()) { 77 if (incoming->GetReadState() == found->GetReadState()) {
77 // Notification matches on the client and the server, nothing to do. 78 // Notification matches on the client and the server, nothing to do.
78 continue; 79 continue;
79 } else { 80 } else {
80 // If the read state is different, read wins for both places. 81 // If the read state is different, read wins for both places.
81 if (incoming->read_state() == SyncedNotification::kDismissed) { 82 if (incoming->GetReadState() == SyncedNotification::kDismissed) {
82 // If it is marked as read on the server, but not the client. 83 // If it is marked as read on the server, but not the client.
83 found->NotificationHasBeenDismissed(); 84 found->NotificationHasBeenDismissed();
84 // TODO(petewil): Tell the Notification UI Manager to mark it read. 85 // TODO(petewil): Tell the Notification UI Manager to mark it read.
85 } else { 86 } else {
86 // If it is marked as read on the client, but not the server. 87 // If it is marked as read on the client, but not the server.
87 syncer::SyncData sync_data = CreateSyncDataFromNotification(*found); 88 syncer::SyncData sync_data = CreateSyncDataFromNotification(*found);
88 new_changes.push_back( 89 new_changes.push_back(
89 syncer::SyncChange(FROM_HERE, 90 syncer::SyncChange(FROM_HERE,
90 syncer::SyncChange::ACTION_UPDATE, 91 syncer::SyncChange::ACTION_UPDATE,
91 sync_data)); 92 sync_data));
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 return error; 169 return error;
169 } 170 }
170 171
171 // Support functions for data type conversion. 172 // Support functions for data type conversion.
172 173
173 // Static method. Get to the sync data in our internal format. 174 // Static method. Get to the sync data in our internal format.
174 syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification( 175 syncer::SyncData ChromeNotifierService::CreateSyncDataFromNotification(
175 const SyncedNotification& notification) { 176 const SyncedNotification& notification) {
176 // Construct the sync_data using the specifics from the notification. 177 // Construct the sync_data using the specifics from the notification.
177 return syncer::SyncData::CreateLocalData( 178 return syncer::SyncData::CreateLocalData(
178 notification.notification_id(), notification.notification_id(), 179 notification.GetKey(), notification.GetKey(),
179 notification.GetEntitySpecifics()); 180 notification.GetEntitySpecifics());
180 } 181 }
181 182
182 // Static Method. Convert from SyncData to our internal format. 183 // Static Method. Convert from SyncData to our internal format.
183 scoped_ptr<SyncedNotification> 184 scoped_ptr<SyncedNotification>
184 ChromeNotifierService::CreateNotificationFromSyncData( 185 ChromeNotifierService::CreateNotificationFromSyncData(
185 const syncer::SyncData& sync_data) { 186 const syncer::SyncData& sync_data) {
186 // Get a pointer to our data within the sync_data object. 187 // Get a pointer to our data within the sync_data object.
187 sync_pb::SyncedNotificationSpecifics specifics = 188 sync_pb::SyncedNotificationSpecifics specifics =
188 sync_data.GetSpecifics().synced_notification(); 189 sync_data.GetSpecifics().synced_notification();
189 190
190 // Check for mandatory fields in the sync_data object. 191 // Check for mandatory fields in the sync_data object.
191 if (!specifics.has_coalesced_notification() || 192 if (!specifics.has_coalesced_notification() ||
192 !specifics.coalesced_notification().has_key() || 193 !specifics.coalesced_notification().has_key() ||
193 !specifics.coalesced_notification().has_read_state()) { 194 !specifics.coalesced_notification().has_read_state())
194 return scoped_ptr<SyncedNotification>(); 195 return scoped_ptr<SyncedNotification>();
195 }
196 196
197 // TODO(petewil): Is this the right set? Should I add more? 197 // TODO(petewil): Is this the right set? Should I add more?
198 bool is_well_formed_unread_notification = 198 bool is_well_formed_unread_notification =
199 (static_cast<SyncedNotification::ReadState>( 199 (static_cast<SyncedNotification::ReadState>(
200 specifics.coalesced_notification().read_state()) == 200 specifics.coalesced_notification().read_state()) ==
201 SyncedNotification::kUnread && 201 SyncedNotification::kUnread &&
202 specifics.coalesced_notification().has_render_info()); 202 specifics.coalesced_notification().has_render_info());
203 bool is_well_formed_dismissed_notification = 203 bool is_well_formed_dismissed_notification =
204 (static_cast<SyncedNotification::ReadState>( 204 (static_cast<SyncedNotification::ReadState>(
205 specifics.coalesced_notification().read_state()) == 205 specifics.coalesced_notification().read_state()) ==
206 SyncedNotification::kDismissed); 206 SyncedNotification::kDismissed);
207 207
208 // if the notification is poorly formed, return a null pointer 208 // if the notification is poorly formed, return a null pointer
209 if (!is_well_formed_unread_notification && 209 if (!is_well_formed_unread_notification &&
210 !is_well_formed_dismissed_notification) 210 !is_well_formed_dismissed_notification)
211 return scoped_ptr<SyncedNotification>(); 211 return scoped_ptr<SyncedNotification>();
212 212
213 // Create a new notification object based on the supplied sync_data. 213 // Create a new notification object based on the supplied sync_data.
214 scoped_ptr<SyncedNotification> notification( 214 scoped_ptr<SyncedNotification> notification(
215 new SyncedNotification(sync_data)); 215 new SyncedNotification(sync_data));
216 216
217 return notification.Pass(); 217 return notification.Pass();
218 } 218 }
219 219
220 // This returns a pointer into a vector that we own. Caller must not free it. 220 // This returns a pointer into a vector that we own. Caller must not free it.
221 // Returns NULL if no match is found. 221 // Returns NULL if no match is found.
222 // This uses the <app_id/coalescing_key> pair as a key. 222 SyncedNotification* ChromeNotifierService::FindNotificationByKey(
223 SyncedNotification* ChromeNotifierService::FindNotificationById( 223 const std::string& key) {
224 const std::string& id) {
225 // TODO(petewil): We can make a performance trade off here. 224 // TODO(petewil): We can make a performance trade off here.
226 // While the vector has good locality of reference, a map has faster lookup. 225 // While the vector has good locality of reference, a map has faster lookup.
227 // Based on how big we expect this to get, maybe change this to a map. 226 // Based on how big we expect this to get, maybe change this to a map.
228 for (std::vector<SyncedNotification*>::const_iterator it = 227 for (std::vector<SyncedNotification*>::const_iterator it =
229 notification_data_.begin(); 228 notification_data_.begin();
230 it != notification_data_.end(); 229 it != notification_data_.end();
231 ++it) { 230 ++it) {
232 SyncedNotification* notification = *it; 231 SyncedNotification* notification = *it;
233 if (id == notification->notification_id()) 232 if (key == notification->GetKey())
234 return *it; 233 return *it;
235 } 234 }
236 235
237 return NULL; 236 return NULL;
238 } 237 }
239 238
240 void ChromeNotifierService::MarkNotificationAsDismissed(const std::string& id) { 239 void ChromeNotifierService::MarkNotificationAsDismissed(
241 SyncedNotification* notification = FindNotificationById(id); 240 const std::string& key) {
241 SyncedNotification* notification = FindNotificationByKey(key);
242 CHECK(notification != NULL); 242 CHECK(notification != NULL);
243 243
244 notification->NotificationHasBeenDismissed(); 244 notification->NotificationHasBeenDismissed();
245 syncer::SyncChangeList new_changes; 245 syncer::SyncChangeList new_changes;
246 246
247 syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification); 247 syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
248 new_changes.push_back( 248 new_changes.push_back(
249 syncer::SyncChange(FROM_HERE, 249 syncer::SyncChange(FROM_HERE,
250 syncer::SyncChange::ACTION_UPDATE, 250 syncer::SyncChange::ACTION_UPDATE,
251 sync_data)); 251 sync_data));
252 252
253 // Send up the changes that were made locally. 253 // Send up the changes that were made locally.
254 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); 254 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
255 } 255 }
256 256
257 // Add a new notification to our data structure. This takes ownership 257 // Add a new notification to our data structure. This takes ownership
258 // of the passed in pointer. 258 // of the passed in pointer.
259 void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) { 259 void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
260 SyncedNotification* notification_copy = notification.get(); 260 SyncedNotification* notification_copy = notification.get();
261 // Take ownership of the object and put it into our local storage. 261 // Take ownership of the object and put it into our local storage.
262 notification_data_.push_back(notification.release()); 262 notification_data_.push_back(notification.release());
263 263
264 // Show it to the user. 264 // Show it to the user.
265 Show(notification_copy); 265 Show(notification_copy);
266 } 266 }
267 267
268 // Send the notification to the NotificationUIManager to show to the user. 268 // Send the notification to the NotificationUIManager to show to the user.
269 void ChromeNotifierService::Show(SyncedNotification* notification) { 269 void ChromeNotifierService::Show(SyncedNotification* notification) {
270 // Set up the fields we need to send and create a Notification object. 270 // Set up the fields we need to send and create a Notification object.
271 GURL origin_url(notification->origin_url()); 271 GURL origin_url(notification->GetOriginUrl());
272 GURL app_icon_url(notification->app_icon_url()); 272 GURL app_icon_url(notification->GetAppIconUrl());
273 string16 title = UTF8ToUTF16(notification->title()); 273 GURL image_url(notification->GetImageUrl());
274 string16 text = UTF8ToUTF16(notification->text()); 274 string16 title = UTF8ToUTF16(notification->GetTitle());
275 string16 heading = UTF8ToUTF16(notification->heading()); 275 string16 text = UTF8ToUTF16(notification->GetText());
276 string16 description = UTF8ToUTF16(notification->description()); 276 string16 heading = UTF8ToUTF16(notification->GetHeading());
277 277 string16 description = UTF8ToUTF16(notification->GetDescription());
278 // TODO(petewil): What goes in the display source, is empty OK? 278 // TODO(petewil): What goes in the display source, is empty OK?
279 string16 display_source; 279 string16 display_source;
280 string16 replace_id = UTF8ToUTF16(notification->notification_id()); 280 string16 replace_key = UTF8ToUTF16(notification->GetKey());
281
282 // TODO(petewil): For now, just punt on dismissed notifications until
283 // I change the interface to let NotificationUIManager know the right way.
284 if (SyncedNotification::kRead == notification->read_state() ||
285 SyncedNotification::kDismissed == notification->read_state() ) {
286 DVLOG(2) << "Not showing dismissed notification"
287 << notification->title() << " " << notification->text();
288 return;
289 }
290 281
291 // The delegate will eventually catch calls that the notification 282 // The delegate will eventually catch calls that the notification
292 // was read or deleted, and send the changes back to the server. 283 // was read or deleted, and send the changes back to the server.
293 scoped_refptr<NotificationDelegate> delegate = 284 scoped_refptr<NotificationDelegate> delegate =
294 new ChromeNotifierDelegate(notification->notification_id(), this); 285 new ChromeNotifierDelegate(notification->GetKey(), this);
295 286
296 Notification ui_notification(origin_url, app_icon_url, heading, description, 287 // Some inputs and fields are only used if there is a notification center.
288 #if defined(ENABLE_MESSAGE_CENTER)
289 double creation_time = static_cast<double>(notification->GetCreationTime());
290 int priority = notification->GetPriority();
291 int notification_count = notification->GetNotificationCount();
292 int button_count = notification->GetButtonCount();
293 std::string button_one_title = notification->GetButtonOneTitle();
294 std::string button_one_icon_url = notification->GetButtonOneIconUrl();
295 std::string button_two_title = notification->GetButtonTwoTitle();
296 std::string button_two_icon_url = notification->GetButtonTwoIconUrl();
297
298 // Deduce which notification template to use from the data.
299 message_center::NotificationType notification_type =
300 message_center::NOTIFICATION_TYPE_SIMPLE;
301 if (!image_url.is_empty()) {
302 notification_type = message_center::NOTIFICATION_TYPE_IMAGE;
303 } else if (notification_count > 1) {
304 notification_type = message_center::NOTIFICATION_TYPE_MULTIPLE;
305 } else if (button_count > 0) {
306 notification_type = message_center::NOTIFICATION_TYPE_BASE_FORMAT;
307 }
308
309 // Fill the optional fields with the information we need to make a
310 // notification.
311 DictionaryValue optional_fields;
312 optional_fields.SetDouble(message_center::kTimestampKey, creation_time);
313 if (priority != SyncedNotification::kUndefinedPriority)
314 optional_fields.SetInteger(message_center::kPriorityKey, priority);
315 if (!button_one_title.empty())
316 optional_fields.SetString(message_center::kButtonOneTitleKey,
317 button_one_title);
318 if (!button_one_icon_url.empty())
319 optional_fields.SetString(message_center::kButtonOneIconUrlKey,
320 button_one_icon_url);
321 if (!button_two_title.empty())
322 optional_fields.SetString(message_center::kButtonTwoTitleKey,
323 button_two_title);
324 if (!button_two_icon_url.empty())
325 optional_fields.SetString(message_center::kButtonTwoIconUrlKey,
326 button_two_icon_url);
327
328 // Fill the individual notification fields for a multiple notification.
329 if (notification_count > 1) {
330 base::ListValue* items = new base::ListValue();
331
332 for (int ii = 0; ii < notification_count; ++ii) {
333 DictionaryValue* item = new DictionaryValue();
334 item->SetString(message_center::kItemTitleKey,
335 UTF8ToUTF16(notification->GetContainedNotificationTitle(
336 ii)));
337 item->SetString(message_center::kItemMessageKey,
338 UTF8ToUTF16(notification->GetContainedNotificationMessage(
339 ii)));
340 items->Append(item);
341 }
342
343 optional_fields.Set(message_center::kItemsKey, items);
344 }
345
346 // TODO(petewil): For now, just punt on dismissed notifications until
347 // I change the interface to let NotificationUIManager know the right way.
348 if (SyncedNotification::kRead == notification->GetReadState() ||
349 SyncedNotification::kDismissed == notification->GetReadState() ) {
350 DVLOG(2) << "Dismissed notification arrived"
351 << notification->GetTitle() << " " << notification->GetText();
352 return;
353 }
354
355 Notification ui_notification(notification_type,
356 origin_url,
357 app_icon_url,
358 heading,
359 text,
297 WebKit::WebTextDirectionDefault, 360 WebKit::WebTextDirectionDefault,
298 display_source, replace_id, delegate); 361 display_source,
362 replace_key,
363 &optional_fields,
364 delegate);
365
366
367 #else // ENABLE_MESSAGE_CENTER
368
369 Notification ui_notification(origin_url,
370 app_icon_url,
371 heading,
372 text,
373 WebKit::WebTextDirectionDefault,
374 display_source,
375 replace_key,
376 delegate);
377
378 #endif // ENABLE_MESSAGE_CENTER
299 379
300 notification_manager_->Add(ui_notification, profile_); 380 notification_manager_->Add(ui_notification, profile_);
301 381
302 DVLOG(1) << "Synced Notification arrived! " << title << " " << text 382 DVLOG(1) << "Synced Notification arrived! " << title << " " << text
303 << " " << app_icon_url << " " << replace_id << " " 383 << " " << app_icon_url << " " << replace_key << " "
304 << notification->read_state(); 384 << notification->GetReadState();
305 385
306 return; 386 return;
307 } 387 }
308 388
309 } // namespace notifier 389 } // namespace notifier
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698