| 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 #include "chrome/browser/notifications/sync_notifier/synced_notification.h" | 5 #include "chrome/browser/notifications/sync_notifier/synced_notification.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 113 |
| 114 return app_icon_ready && images_ready && sender_picture_ready && | 114 return app_icon_ready && images_ready && sender_picture_ready && |
| 115 button_bitmaps_ready; | 115 button_bitmaps_ready; |
| 116 } | 116 } |
| 117 | 117 |
| 118 // TODO(petewil): The fetch mechanism appears to be returning two bitmaps on the | 118 // TODO(petewil): The fetch mechanism appears to be returning two bitmaps on the |
| 119 // mac - perhaps one is regular, one is high dpi? If so, ensure we use the high | 119 // mac - perhaps one is regular, one is high dpi? If so, ensure we use the high |
| 120 // dpi bitmap when appropriate. | 120 // dpi bitmap when appropriate. |
| 121 void SyncedNotification::OnFetchComplete(const GURL url, | 121 void SyncedNotification::OnFetchComplete(const GURL url, |
| 122 const SkBitmap* bitmap) { | 122 const SkBitmap* bitmap) { |
| 123 // TODO(petewil): Add timeout mechanism in case bitmaps take too long. Do we | |
| 124 // already have one built into URLFetcher? | |
| 125 // Make sure we are on the thread we expect. | 123 // Make sure we are on the thread we expect. |
| 126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 124 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 127 | 125 |
| 128 gfx::Image downloaded_image; | 126 gfx::Image downloaded_image; |
| 129 if (bitmap != NULL) | 127 if (bitmap != NULL) |
| 130 downloaded_image = gfx::Image::CreateFrom1xBitmap(*bitmap); | 128 downloaded_image = gfx::Image::CreateFrom1xBitmap(*bitmap); |
| 131 | 129 |
| 132 // Match the incoming bitmaps to URLs. In case this is a dup, make sure to | 130 // Match the incoming bitmaps to URLs. In case this is a dup, make sure to |
| 133 // try all potentially matching urls. | 131 // try all potentially matching urls. |
| 134 if (GetAppIconUrl() == url) { | 132 if (GetAppIconUrl() == url) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 154 button_bitmaps_[i] = gfx::Image::CreateFrom1xBitmap(*bitmap); | 152 button_bitmaps_[i] = gfx::Image::CreateFrom1xBitmap(*bitmap); |
| 155 } | 153 } |
| 156 button_bitmaps_fetch_pending_[i] = false; | 154 button_bitmaps_fetch_pending_[i] = false; |
| 157 } | 155 } |
| 158 } | 156 } |
| 159 | 157 |
| 160 DVLOG(2) << __FUNCTION__ << " popping bitmap " << url; | 158 DVLOG(2) << __FUNCTION__ << " popping bitmap " << url; |
| 161 | 159 |
| 162 // See if all bitmaps are already accounted for, if so call Show. | 160 // See if all bitmaps are already accounted for, if so call Show. |
| 163 if (AreAllBitmapsFetched()) { | 161 if (AreAllBitmapsFetched()) { |
| 164 Show(notification_manager_, notifier_service_, profile_); | 162 Show(profile_); |
| 165 } | 163 } |
| 166 } | 164 } |
| 167 | 165 |
| 168 void SyncedNotification::QueueBitmapFetchJobs( | 166 void SyncedNotification::QueueBitmapFetchJobs( |
| 169 NotificationUIManager* notification_manager, | |
| 170 ChromeNotifierService* notifier_service, | 167 ChromeNotifierService* notifier_service, |
| 171 Profile* profile) { | 168 Profile* profile) { |
| 172 // If we are not using the MessageCenter, call show now, and the existing | 169 // If we are not using the MessageCenter, call show now, and the existing |
| 173 // code will handle the bitmap fetch for us. | 170 // code will handle the bitmap fetch for us. |
| 174 if (!UseRichNotifications()) { | 171 if (!UseRichNotifications()) { |
| 175 Show(notification_manager, notifier_service, profile); | 172 Show(profile); |
| 176 return; | 173 return; |
| 177 } | 174 } |
| 178 | 175 |
| 179 // Save off the arguments for the call to Show. | 176 // Save off the arguments for the call to Show. |
| 180 notification_manager_ = notification_manager; | |
| 181 notifier_service_ = notifier_service; | 177 notifier_service_ = notifier_service; |
| 182 profile_ = profile; | 178 profile_ = profile; |
| 183 | 179 |
| 184 // Ensure our bitmap vector has as many entries as there are buttons, | 180 // Ensure our bitmap vector has as many entries as there are buttons, |
| 185 // so that when the bitmaps arrive the vector has a slot for them. | 181 // so that when the bitmaps arrive the vector has a slot for them. |
| 186 for (unsigned int i = 0; i < GetButtonCount(); ++i) { | 182 for (unsigned int i = 0; i < GetButtonCount(); ++i) { |
| 187 button_bitmaps_.push_back(gfx::Image()); | 183 button_bitmaps_.push_back(gfx::Image()); |
| 188 button_bitmaps_fetch_pending_.push_back(true); | 184 button_bitmaps_fetch_pending_.push_back(true); |
| 189 AddBitmapToFetchQueue(GetButtonIconUrl(i)); | 185 CreateBitmapFetcher(GetButtonIconUrl(i)); |
| 190 } | 186 } |
| 191 | 187 |
| 192 // If there is a profile image bitmap, fetch it | 188 // If there is a profile image bitmap, fetch it |
| 193 if (GetProfilePictureCount() > 0) { | 189 if (GetProfilePictureCount() > 0) { |
| 194 // TODO(petewil): When we have the capacity to display more than one bitmap, | 190 // TODO(petewil): When we have the capacity to display more than one bitmap, |
| 195 // modify this code to fetch as many as we can display | 191 // modify this code to fetch as many as we can display |
| 196 AddBitmapToFetchQueue(GetProfilePictureUrl(0)); | 192 CreateBitmapFetcher(GetProfilePictureUrl(0)); |
| 197 } | 193 } |
| 198 | 194 |
| 199 // If the URL is non-empty, add it to our queue of URLs to fetch. | 195 // If the URL is non-empty, add it to our queue of URLs to fetch. |
| 200 AddBitmapToFetchQueue(GetAppIconUrl()); | 196 CreateBitmapFetcher(GetAppIconUrl()); |
| 201 AddBitmapToFetchQueue(GetImageUrl()); | 197 CreateBitmapFetcher(GetImageUrl()); |
| 202 | 198 |
| 203 // Check to see if we don't need to fetch images, either because we already | 199 // Check to see if we don't need to fetch images, either because we already |
| 204 // did, or because the URLs are empty. If so, we can display the notification. | 200 // did, or because the URLs are empty. If so, we can display the notification. |
| 205 | 201 |
| 206 // See if all bitmaps are accounted for, if so call Show(). | 202 // See if all bitmaps are accounted for, if so call Show(). |
| 207 if (AreAllBitmapsFetched()) { | 203 if (AreAllBitmapsFetched()) { |
| 208 Show(notification_manager_, notifier_service_, profile_); | 204 Show(profile_); |
| 209 } | 205 } |
| 210 } | 206 } |
| 211 | 207 |
| 212 void SyncedNotification::StartBitmapFetch() { | 208 void SyncedNotification::StartBitmapFetch() { |
| 213 // Now that we have queued and counted them all, start the fetching. | 209 // Now that we have queued and counted them all, start the fetching. |
| 214 ScopedVector<chrome::BitmapFetcher>::iterator iter; | 210 ScopedVector<chrome::BitmapFetcher>::iterator iter; |
| 215 for (iter = fetchers_.begin(); iter != fetchers_.end(); ++iter) { | 211 for (iter = fetchers_.begin(); iter != fetchers_.end(); ++iter) { |
| 216 (*iter)->Start(profile_); | 212 (*iter)->Start(profile_); |
| 217 } | 213 } |
| 218 } | 214 } |
| 219 | 215 |
| 220 void SyncedNotification::AddBitmapToFetchQueue(const GURL& url) { | 216 void SyncedNotification::CreateBitmapFetcher(const GURL& url) { |
| 221 // Check for dups, ignore any request for a dup. | 217 // Check for dups, ignore any request for a dup. |
| 222 ScopedVector<chrome::BitmapFetcher>::iterator iter; | 218 ScopedVector<chrome::BitmapFetcher>::iterator iter; |
| 223 for (iter = fetchers_.begin(); iter != fetchers_.end(); ++iter) { | 219 for (iter = fetchers_.begin(); iter != fetchers_.end(); ++iter) { |
| 224 if ((*iter)->url() == url) | 220 if ((*iter)->url() == url) |
| 225 return; | 221 return; |
| 226 } | 222 } |
| 227 | 223 |
| 228 if (url.is_valid()) { | 224 if (url.is_valid()) { |
| 229 fetchers_.push_back(new chrome::BitmapFetcher(url, this)); | 225 fetchers_.push_back(new chrome::BitmapFetcher(url, this)); |
| 230 DVLOG(2) << __FUNCTION__ << "Pushing bitmap " << url; | 226 DVLOG(2) << __FUNCTION__ << "Pushing bitmap " << url; |
| 231 } | 227 } |
| 232 } | 228 } |
| 233 | 229 |
| 234 void SyncedNotification::Show(NotificationUIManager* notification_manager, | 230 void SyncedNotification::Show(Profile* profile) { |
| 235 ChromeNotifierService* notifier_service, | |
| 236 Profile* profile) { | |
| 237 // Let NotificationUIManager know that the notification has been dismissed. | 231 // Let NotificationUIManager know that the notification has been dismissed. |
| 238 if (SyncedNotification::kRead == GetReadState() || | 232 if (SyncedNotification::kRead == GetReadState() || |
| 239 SyncedNotification::kDismissed == GetReadState() ) { | 233 SyncedNotification::kDismissed == GetReadState() ) { |
| 240 notification_manager->CancelById(GetKey()); | 234 notification_manager_->CancelById(GetKey()); |
| 241 DVLOG(2) << "Dismissed or read notification arrived" | 235 DVLOG(2) << "Dismissed or read notification arrived" |
| 242 << GetHeading() << " " << GetText(); | 236 << GetHeading() << " " << GetText(); |
| 243 return; | 237 return; |
| 244 } | 238 } |
| 245 | 239 |
| 246 // |notifier_service| can be NULL in tests. | 240 // |notifier_service| can be NULL in tests. |
| 247 if (UseRichNotifications() && notifier_service) { | 241 if (UseRichNotifications() && notifier_service_) { |
| 248 notifier_service->ShowWelcomeToastIfNecessary(this, notification_manager); | 242 notifier_service_->ShowWelcomeToastIfNecessary(this, notification_manager_); |
| 249 } | 243 } |
| 250 | 244 |
| 251 // Set up the fields we need to send and create a Notification object. | 245 // Set up the fields we need to send and create a Notification object. |
| 252 GURL image_url = GetImageUrl(); | 246 GURL image_url = GetImageUrl(); |
| 253 base::string16 text = base::UTF8ToUTF16(GetText()); | 247 base::string16 text = base::UTF8ToUTF16(GetText()); |
| 254 base::string16 heading = base::UTF8ToUTF16(GetHeading()); | 248 base::string16 heading = base::UTF8ToUTF16(GetHeading()); |
| 255 base::string16 description = base::UTF8ToUTF16(GetDescription()); | 249 base::string16 description = base::UTF8ToUTF16(GetDescription()); |
| 256 base::string16 annotation = base::UTF8ToUTF16(GetAnnotation()); | 250 base::string16 annotation = base::UTF8ToUTF16(GetAnnotation()); |
| 257 // TODO(petewil): Eventually put the display name of the sending service here. | 251 // TODO(petewil): Eventually put the display name of the sending service here. |
| 258 base::string16 display_source = base::UTF8ToUTF16(GetAppId()); | 252 base::string16 display_source = base::UTF8ToUTF16(GetAppId()); |
| 259 base::string16 replace_key = base::UTF8ToUTF16(GetKey()); | 253 base::string16 replace_key = base::UTF8ToUTF16(GetKey()); |
| 260 base::string16 notification_heading = heading; | 254 base::string16 notification_heading = heading; |
| 261 base::string16 notification_text = description; | 255 base::string16 notification_text = description; |
| 262 base::string16 newline = base::UTF8ToUTF16("\n"); | 256 base::string16 newline = base::UTF8ToUTF16("\n"); |
| 263 | 257 |
| 264 // The delegate will eventually catch calls that the notification | 258 // The delegate will eventually catch calls that the notification |
| 265 // was read or deleted, and send the changes back to the server. | 259 // was read or deleted, and send the changes back to the server. |
| 266 scoped_refptr<NotificationDelegate> delegate = | 260 scoped_refptr<NotificationDelegate> delegate = |
| 267 new ChromeNotifierDelegate(GetKey(), notifier_service); | 261 new ChromeNotifierDelegate(GetKey(), notifier_service_); |
| 268 | 262 |
| 269 // Some inputs and fields are only used if there is a notification center. | 263 // Some inputs and fields are only used if there is a notification center. |
| 270 if (UseRichNotifications()) { | 264 if (UseRichNotifications()) { |
| 271 base::Time creation_time = | 265 base::Time creation_time = |
| 272 base::Time::FromDoubleT(static_cast<double>(GetCreationTime())); | 266 base::Time::FromDoubleT(static_cast<double>(GetCreationTime())); |
| 273 int priority = GetPriority(); | 267 int priority = GetPriority(); |
| 274 unsigned int button_count = GetButtonCount(); | 268 unsigned int button_count = GetButtonCount(); |
| 275 | 269 |
| 276 // Deduce which notification template to use from the data. | 270 // Deduce which notification template to use from the data. |
| 277 message_center::NotificationType notification_type = | 271 message_center::NotificationType notification_type = |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 blink::WebTextDirectionDefault, | 351 blink::WebTextDirectionDefault, |
| 358 message_center::NotifierId(GetOriginUrl()), | 352 message_center::NotifierId(GetOriginUrl()), |
| 359 display_source, | 353 display_source, |
| 360 replace_key, | 354 replace_key, |
| 361 rich_notification_data, | 355 rich_notification_data, |
| 362 delegate.get()); | 356 delegate.get()); |
| 363 // In case the notification is not supposed to be toasted, pretend that it | 357 // In case the notification is not supposed to be toasted, pretend that it |
| 364 // has already been shown. | 358 // has already been shown. |
| 365 ui_notification.set_shown_as_popup(!toast_state_); | 359 ui_notification.set_shown_as_popup(!toast_state_); |
| 366 | 360 |
| 367 notification_manager->Add(ui_notification, profile); | 361 notification_manager_->Add(ui_notification, profile); |
| 368 } else { | 362 } else { |
| 369 // In this case we have a Webkit Notification, not a Rich Notification. | 363 // In this case we have a Webkit Notification, not a Rich Notification. |
| 370 Notification ui_notification(GetOriginUrl(), | 364 Notification ui_notification(GetOriginUrl(), |
| 371 GetAppIconUrl(), | 365 GetAppIconUrl(), |
| 372 notification_heading, | 366 notification_heading, |
| 373 notification_text, | 367 notification_text, |
| 374 blink::WebTextDirectionDefault, | 368 blink::WebTextDirectionDefault, |
| 375 display_source, | 369 display_source, |
| 376 replace_key, | 370 replace_key, |
| 377 delegate.get()); | 371 delegate.get()); |
| 378 | 372 |
| 379 notification_manager->Add(ui_notification, profile); | 373 notification_manager_->Add(ui_notification, profile); |
| 380 } | 374 } |
| 381 | 375 |
| 382 DVLOG(1) << "Showing Synced Notification! " << heading << " " << text | 376 DVLOG(1) << "Showing Synced Notification! " << heading << " " << text |
| 383 << " " << GetAppIconUrl() << " " << replace_key << " " | 377 << " " << GetAppIconUrl() << " " << replace_key << " " |
| 384 << GetProfilePictureUrl(0) << " " << GetReadState(); | 378 << GetProfilePictureUrl(0) << " " << GetReadState(); |
| 385 | 379 |
| 386 return; | 380 return; |
| 387 } | 381 } |
| 388 | 382 |
| 383 // Display the notification if it has the specified app_id_name. |
| 384 void SyncedNotification::ShowAllForAppId(Profile* profile, |
| 385 std::string app_id_name) { |
| 386 if (app_id_name == GetAppId()) |
| 387 Show(profile); |
| 388 } |
| 389 |
| 390 // Remove the notification if it has the specified app_id_name. |
| 391 void SyncedNotification::HideAllForAppId(std::string app_id_name) { |
| 392 if (app_id_name == GetAppId()) { |
| 393 notification_manager_->CancelById(GetKey()); |
| 394 } |
| 395 } |
| 396 |
| 389 // This should detect even small changes in case the server updated the | 397 // This should detect even small changes in case the server updated the |
| 390 // notification. We ignore the timestamp if other fields match. | 398 // notification. We ignore the timestamp if other fields match. |
| 391 bool SyncedNotification::EqualsIgnoringReadState( | 399 bool SyncedNotification::EqualsIgnoringReadState( |
| 392 const SyncedNotification& other) const { | 400 const SyncedNotification& other) const { |
| 393 if (GetTitle() == other.GetTitle() && | 401 if (GetTitle() == other.GetTitle() && |
| 394 GetHeading() == other.GetHeading() && | 402 GetHeading() == other.GetHeading() && |
| 395 GetDescription() == other.GetDescription() && | 403 GetDescription() == other.GetDescription() && |
| 396 GetAnnotation() == other.GetAnnotation() && | 404 GetAnnotation() == other.GetAnnotation() && |
| 397 GetAppId() == other.GetAppId() && | 405 GetAppId() == other.GetAppId() && |
| 398 GetKey() == other.GetKey() && | 406 GetKey() == other.GetKey() && |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 std::string SyncedNotification::GetContainedNotificationMessage( | 747 std::string SyncedNotification::GetContainedNotificationMessage( |
| 740 int index) const { | 748 int index) const { |
| 741 if (specifics_.coalesced_notification().render_info().expanded_info(). | 749 if (specifics_.coalesced_notification().render_info().expanded_info(). |
| 742 collapsed_info_size() < index + 1) | 750 collapsed_info_size() < index + 1) |
| 743 return std::string(); | 751 return std::string(); |
| 744 | 752 |
| 745 return specifics_.coalesced_notification().render_info().expanded_info(). | 753 return specifics_.coalesced_notification().render_info().expanded_info(). |
| 746 collapsed_info(index).simple_collapsed_layout().description(); | 754 collapsed_info(index).simple_collapsed_layout().description(); |
| 747 } | 755 } |
| 748 | 756 |
| 749 std::string SyncedNotification::GetSendingServiceId() const { | |
| 750 // TODO(petewil): We are building a new protocol (a new sync datatype) to send | |
| 751 // the service name and icon from the server. For now this method is | |
| 752 // hardcoded to the name of our first service using synced notifications. | |
| 753 // Once the new protocol is built, remove this hardcoding. | |
| 754 return kFirstSyncedNotificationServiceId; | |
| 755 } | |
| 756 | |
| 757 const gfx::Image& SyncedNotification::GetAppIcon() const { | 757 const gfx::Image& SyncedNotification::GetAppIcon() const { |
| 758 return app_icon_bitmap_; | 758 return app_icon_bitmap_; |
| 759 } | 759 } |
| 760 | 760 |
| 761 void SyncedNotification::SetToastState(bool toast_state) { | 761 void SyncedNotification::SetToastState(bool toast_state) { |
| 762 toast_state_ = toast_state; | 762 toast_state_ = toast_state; |
| 763 } | 763 } |
| 764 | 764 |
| 765 } // namespace notifier | 765 } // namespace notifier |
| OLD | NEW |