OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/download/notification/download_notification_item.h" |
| 6 |
| 7 #include "base/strings/string_number_conversions.h" |
| 8 #include "chrome/browser/download/download_crx_util.h" |
| 9 #include "chrome/browser/download/download_item_model.h" |
| 10 #include "chrome/grit/chromium_strings.h" |
| 11 #include "chrome/grit/generated_resources.h" |
| 12 #include "content/public/browser/browser_thread.h" |
| 13 #include "content/public/browser/download_item.h" |
| 14 #include "grit/theme_resources.h" |
| 15 #include "ui/base/l10n/l10n_util.h" |
| 16 #include "ui/base/resource/resource_bundle.h" |
| 17 #include "ui/message_center/message_center.h" |
| 18 #include "ui/message_center/notification.h" |
| 19 #include "ui/message_center/notification_delegate.h" |
| 20 |
| 21 using message_center::Notification; |
| 22 |
| 23 namespace { |
| 24 |
| 25 const char kDownloadNotificationNotifierId[] = |
| 26 "chrome://settings/display/notification/id-notifier"; |
| 27 const char kDownloadNotificationIdBase[] = |
| 28 "chrome://settings/display/notification/id-"; |
| 29 |
| 30 } // anonymous namespace |
| 31 |
| 32 DownloadNotificationItem::DownloadNotificationItem( |
| 33 content::DownloadItem* item, |
| 34 Delegate* delegate) : |
| 35 openable_(false), |
| 36 downloading_(false), |
| 37 image_resource_id_(0), |
| 38 item_(item), |
| 39 delegate_(delegate) { |
| 40 item->AddObserver(this); |
| 41 |
| 42 message_center_ = message_center::MessageCenter::Get(); |
| 43 |
| 44 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
| 45 |
| 46 const base::string16 timeout_message = |
| 47 l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING); |
| 48 const base::string16 message = |
| 49 l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); |
| 50 |
| 51 std::string id(kDownloadNotificationIdBase); |
| 52 id += base::UintToString(item->GetId()); |
| 53 |
| 54 message_center::RichNotificationData data; |
| 55 notification_.reset(new Notification( |
| 56 message_center::NOTIFICATION_TYPE_PROGRESS, |
| 57 id, |
| 58 message, |
| 59 timeout_message, |
| 60 bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING), |
| 61 base::string16() /* display_source */, |
| 62 message_center::NotifierId( |
| 63 message_center::NotifierId::SYSTEM_COMPONENT, |
| 64 kDownloadNotificationNotifierId), |
| 65 data, |
| 66 this)); |
| 67 |
| 68 notification_->set_progress(0); |
| 69 notification_->set_never_timeout(false); |
| 70 |
| 71 SetNotificationData(); |
| 72 |
| 73 scoped_ptr<Notification> notification(new Notification(*notification_)); |
| 74 message_center_->AddNotification(notification.Pass()); |
| 75 } |
| 76 |
| 77 DownloadNotificationItem::~DownloadNotificationItem() { |
| 78 } |
| 79 |
| 80 void DownloadNotificationItem::Close(bool by_user) { |
| 81 bool is_popup = false; |
| 82 |
| 83 const std::string id = notification_->id(); |
| 84 message_center::NotificationList::PopupNotifications popups = |
| 85 message_center_->GetPopupNotifications(); |
| 86 for (auto it = popups.begin(); it != popups.end(); it++) { |
| 87 if ((*it)->id() == id) { |
| 88 is_popup = true; |
| 89 } |
| 90 } |
| 91 LOG(ERROR) << "CLOSE: " << is_popup; |
| 92 |
| 93 if (is_popup) { |
| 94 notification_->set_is_read(true); |
| 95 ShowNotificationAgainSoon(); |
| 96 } else { |
| 97 item_->RemoveObserver(this); |
| 98 item_->Cancel(by_user); |
| 99 delegate_->OnDownloadNotificationItemDestroying(this); |
| 100 } |
| 101 } |
| 102 |
| 103 void DownloadNotificationItem::ShowNotificationAgainSoon() { |
| 104 content::BrowserThread::PostTask( |
| 105 content::BrowserThread::UI, |
| 106 FROM_HERE, |
| 107 base::Bind(&DownloadNotificationItem::ShowNotificationAgain, this)); |
| 108 } |
| 109 |
| 110 void DownloadNotificationItem::ShowNotificationAgain() { |
| 111 scoped_ptr<Notification> notification(new Notification(*notification_)); |
| 112 message_center_->AddNotification(notification.Pass()); |
| 113 message_center_->MarkSinglePopupAsShown( |
| 114 notification_->id(), notification_->IsRead()); |
| 115 } |
| 116 |
| 117 void DownloadNotificationItem::Click() { |
| 118 if (openable_) |
| 119 item_->OpenDownload(); |
| 120 if (item_->IsDone()) { |
| 121 message_center_->RemoveNotification(notification_->id(), true); |
| 122 } |
| 123 } |
| 124 |
| 125 bool DownloadNotificationItem::HasClickedListener() { |
| 126 return true; |
| 127 } |
| 128 |
| 129 void DownloadNotificationItem::ButtonClick(int button_index) { |
| 130 if (button_index < 0 || |
| 131 static_cast<size_t>(button_index) >= button_actions_->size()) { |
| 132 // Out of boundary. Do nothing. |
| 133 return; |
| 134 } |
| 135 |
| 136 switch (button_actions_->at(button_index)) { |
| 137 case OPEN_WHEN_COMPLETE: |
| 138 NOTREACHED(); |
| 139 break; |
| 140 case PAUSE: |
| 141 item_->Pause(); |
| 142 break; |
| 143 case RESUME: |
| 144 case RETRY: |
| 145 item_->Resume(); |
| 146 break; |
| 147 case SHOW_IN_FOLDER: |
| 148 item_->ShowDownloadInShell(); |
| 149 break; |
| 150 case DISCARD: |
| 151 item_->Cancel(true); |
| 152 break; |
| 153 default: |
| 154 break; |
| 155 } |
| 156 } |
| 157 |
| 158 // DownloadItem::Observer methods |
| 159 void DownloadNotificationItem::OnDownloadUpdated(content::DownloadItem* item) { |
| 160 DCHECK_EQ(item, item_); |
| 161 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 162 |
| 163 SetNotificationData(); |
| 164 |
| 165 // Updates notification. |
| 166 scoped_ptr<Notification> notification(new Notification(*notification_)); |
| 167 message_center_->UpdateNotification( |
| 168 notification->id(), |
| 169 notification.Pass()); |
| 170 } |
| 171 |
| 172 void DownloadNotificationItem::SetNotificationData() { |
| 173 DownloadItemModel* model = new DownloadItemModel(item_); |
| 174 |
| 175 if (!downloading_) { |
| 176 if (item_->GetState() != content::DownloadItem::IN_PROGRESS) |
| 177 delegate_->OnDownloadStarted(this); |
| 178 } else { |
| 179 if (item_->GetState() != content::DownloadItem::IN_PROGRESS) |
| 180 delegate_->OnDownloadStopped(this); |
| 181 } |
| 182 |
| 183 if (item_->IsDangerous()) { |
| 184 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); |
| 185 notification_->set_title(GetTitle()); |
| 186 notification_->set_message(GetWarningTextLong()); |
| 187 |
| 188 // Show icon. |
| 189 |
| 190 switch (item_->GetDangerType()) { |
| 191 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: |
| 192 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: |
| 193 break; |
| 194 default: |
| 195 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS); |
| 196 break; |
| 197 } |
| 198 } else { |
| 199 notification_->set_title(GetTitle()); |
| 200 notification_->set_message(model->GetStatusText()); |
| 201 |
| 202 switch (item_->GetState()) { |
| 203 case content::DownloadItem::IN_PROGRESS: |
| 204 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); |
| 205 notification_->set_progress(item_->PercentComplete()); |
| 206 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); |
| 207 break; |
| 208 case content::DownloadItem::COMPLETE: |
| 209 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); |
| 210 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); |
| 211 |
| 212 // TODO(yoshiki): Popup a notification again. |
| 213 break; |
| 214 case content::DownloadItem::CANCELLED: |
| 215 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); |
| 216 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_WARNING); |
| 217 break; |
| 218 case content::DownloadItem::INTERRUPTED: |
| 219 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); |
| 220 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_WARNING); |
| 221 |
| 222 // TODO(yoshiki): Popup a notification again. |
| 223 break; |
| 224 case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel |
| 225 NOTREACHED(); |
| 226 } |
| 227 } |
| 228 |
| 229 std::vector<message_center::ButtonInfo> notification_actions; |
| 230 scoped_ptr<std::vector<DownloadCommands> > |
| 231 actions(GetPossibleActions().Pass()); |
| 232 |
| 233 openable_ = false; |
| 234 button_actions_.reset(new std::vector<DownloadCommands>); |
| 235 ResourceBundle& bundle = ResourceBundle::GetSharedInstance(); |
| 236 for (auto it = actions->begin(); it != actions->end(); it++) { |
| 237 switch (*it) { |
| 238 case OPEN_WHEN_COMPLETE: |
| 239 openable_ = true; |
| 240 break; |
| 241 default: |
| 242 button_actions_->push_back(*it); |
| 243 message_center::ButtonInfo button_info = |
| 244 message_center::ButtonInfo(GetCommandText(*it)); |
| 245 button_info.icon = bundle.GetImageNamed(GetCommandIconId(*it)); |
| 246 notification_actions.push_back(button_info); |
| 247 break; |
| 248 } |
| 249 } |
| 250 notification_->set_buttons(notification_actions); |
| 251 |
| 252 if (item_->IsDone()) { |
| 253 // TODO(yoshiki): If the downloaded file is an image, show the thumbnail. |
| 254 } |
| 255 } |
| 256 |
| 257 void DownloadNotificationItem::OnDownloadOpened(content::DownloadItem* item) { |
| 258 DCHECK_EQ(item, item_); |
| 259 // Do nothing. |
| 260 } |
| 261 |
| 262 void DownloadNotificationItem::OnDownloadDestroyed( |
| 263 content::DownloadItem* item) { |
| 264 DCHECK_EQ(item, item_); |
| 265 LOG(ERROR) << "ONDOWNLOADDESTROYED"; |
| 266 |
| 267 // TODO(yoshiki): close the notification if necessary. |
| 268 |
| 269 delegate_->OnDownloadNotificationItemDestroying(this); |
| 270 } |
| 271 |
| 272 void DownloadNotificationItem::SetImageToNotification(int resource_id) { |
| 273 if (image_resource_id_ == resource_id) |
| 274 return; |
| 275 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
| 276 image_resource_id_ = resource_id; |
| 277 notification_->set_small_image(bundle.GetImageNamed(image_resource_id_)); |
| 278 } |
| 279 |
| 280 scoped_ptr<std::vector<DownloadCommands> > |
| 281 DownloadNotificationItem::GetPossibleActions() const { |
| 282 scoped_ptr<std::vector<DownloadCommands> > |
| 283 actions(new std::vector<DownloadCommands>()); |
| 284 |
| 285 if (item_->IsDangerous()) { |
| 286 actions->push_back(DISCARD); |
| 287 actions->push_back(SHOW_IN_FOLDER); |
| 288 return actions.Pass(); |
| 289 } |
| 290 |
| 291 switch (item_->GetState()) { |
| 292 case content::DownloadItem::IN_PROGRESS: |
| 293 actions->push_back(OPEN_WHEN_COMPLETE); |
| 294 if (!item_->IsPaused()) |
| 295 actions->push_back(PAUSE); |
| 296 else |
| 297 actions->push_back(RESUME); |
| 298 break; |
| 299 case content::DownloadItem::CANCELLED: |
| 300 case content::DownloadItem::INTERRUPTED: |
| 301 actions->push_back(RETRY); |
| 302 break; |
| 303 case content::DownloadItem::COMPLETE: |
| 304 actions->push_back(OPEN_WHEN_COMPLETE); |
| 305 actions->push_back(SHOW_IN_FOLDER); |
| 306 break; |
| 307 case content::DownloadItem::MAX_DOWNLOAD_STATE: |
| 308 NOTREACHED(); |
| 309 } |
| 310 return actions.Pass(); |
| 311 } |
| 312 |
| 313 base::string16 DownloadNotificationItem::GetTitle() const { |
| 314 base::string16 title_text; |
| 315 base::string16 file_name = |
| 316 item_->GetFileNameToReportUser().LossyDisplayName(); |
| 317 switch (item_->GetState()) { |
| 318 case content::DownloadItem::IN_PROGRESS: |
| 319 title_text = l10n_util::GetStringFUTF16( |
| 320 IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE, |
| 321 file_name); |
| 322 break; |
| 323 case content::DownloadItem::COMPLETE: |
| 324 title_text = l10n_util::GetStringFUTF16( |
| 325 IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE, |
| 326 file_name); |
| 327 case content::DownloadItem::INTERRUPTED: |
| 328 title_text = l10n_util::GetStringFUTF16( |
| 329 IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE, |
| 330 file_name); |
| 331 break; |
| 332 case content::DownloadItem::CANCELLED: |
| 333 title_text = l10n_util::GetStringFUTF16( |
| 334 IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE, |
| 335 file_name); |
| 336 break; |
| 337 case content::DownloadItem::MAX_DOWNLOAD_STATE: |
| 338 NOTREACHED(); |
| 339 } |
| 340 return title_text; |
| 341 } |
| 342 |
| 343 base::string16 DownloadNotificationItem::GetWarningTextLong() const { |
| 344 // Should only be called if IsDangerous(). |
| 345 DCHECK(item_->IsDangerous()); |
| 346 base::string16 elided_filename = |
| 347 item_->GetFileNameToReportUser().LossyDisplayName(); |
| 348 switch (item_->GetDangerType()) { |
| 349 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: { |
| 350 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); |
| 351 } |
| 352 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: { |
| 353 if (download_crx_util::IsExtensionDownload(*item_)) { |
| 354 return l10n_util::GetStringUTF16( |
| 355 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION); |
| 356 } else { |
| 357 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, |
| 358 elided_filename); |
| 359 } |
| 360 } |
| 361 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: |
| 362 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { |
| 363 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, |
| 364 elided_filename); |
| 365 } |
| 366 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { |
| 367 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, |
| 368 elided_filename); |
| 369 } |
| 370 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { |
| 371 return l10n_util::GetStringFUTF16( |
| 372 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename); |
| 373 } |
| 374 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: |
| 375 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: |
| 376 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: |
| 377 case content::DOWNLOAD_DANGER_TYPE_MAX: { |
| 378 break; |
| 379 } |
| 380 } |
| 381 NOTREACHED(); |
| 382 return base::string16(); |
| 383 } |
| 384 |
OLD | NEW |