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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/download/download_item_model.h" 6 7 #include "base/i18n/number_formatting.h" 8 #include "base/i18n/rtl.h" 9 #include "base/metrics/field_trial.h" 10 #include "base/strings/string16.h" 11 #include "base/strings/sys_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/supports_user_data.h" 14 #include "base/time/time.h" 15 #include "chrome/browser/download/chrome_download_manager_delegate.h" 16 #include "chrome/browser/download/download_crx_util.h" 17 #include "chrome/browser/download/download_history.h" 18 #include "chrome/browser/download/download_service.h" 19 #include "chrome/browser/download/download_service_factory.h" 20 #include "chrome/browser/download/download_stats.h" 21 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/safe_browsing/download_feedback_service.h" 23 #include "content/public/browser/download_danger_type.h" 24 #include "content/public/browser/download_interrupt_reasons.h" 25 #include "content/public/browser/download_item.h" 26 #include "grit/chromium_strings.h" 27 #include "grit/generated_resources.h" 28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/time_format.h" 30 #include "ui/base/text/bytes_formatting.h" 31 #include "ui/gfx/text_elider.h" 32 33 using base::TimeDelta; 34 using content::DownloadItem; 35 36 namespace { 37 38 // Per DownloadItem data used by DownloadItemModel. The model doesn't keep any 39 // state since there could be multiple models associated with a single 40 // DownloadItem, and the lifetime of the model is shorter than the DownloadItem. 41 class DownloadItemModelData : public base::SupportsUserData::Data { 42 public: 43 // Get the DownloadItemModelData object for |download|. Returns NULL if 44 // there's no model data. 45 static const DownloadItemModelData* Get(const DownloadItem* download); 46 47 // Get the DownloadItemModelData object for |download|. Creates a model data 48 // object if not found. Always returns a non-NULL pointer, unless OOM. 49 static DownloadItemModelData* GetOrCreate(DownloadItem* download); 50 51 bool should_show_in_shelf() const { return should_show_in_shelf_; } 52 void set_should_show_in_shelf(bool should_show_in_shelf) { 53 should_show_in_shelf_ = should_show_in_shelf; 54 } 55 56 bool was_ui_notified() const { return was_ui_notified_; } 57 void set_was_ui_notified(bool was_ui_notified) { 58 was_ui_notified_ = was_ui_notified; 59 } 60 61 bool should_prefer_opening_in_browser() const { 62 return should_prefer_opening_in_browser_; 63 } 64 void set_should_prefer_opening_in_browser(bool preference) { 65 should_prefer_opening_in_browser_ = preference; 66 } 67 68 private: 69 DownloadItemModelData(); 70 virtual ~DownloadItemModelData() {} 71 72 static const char kKey[]; 73 74 // Whether the download should be displayed in the download shelf. True by 75 // default. 76 bool should_show_in_shelf_; 77 78 // Whether the UI has been notified about this download. 79 bool was_ui_notified_; 80 81 // Whether the download should be opened in the browser vs. the system handler 82 // for the file type. 83 bool should_prefer_opening_in_browser_; 84 }; 85 86 // static 87 const char DownloadItemModelData::kKey[] = "DownloadItemModelData key"; 88 89 // static 90 const DownloadItemModelData* DownloadItemModelData::Get( 91 const DownloadItem* download) { 92 return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey)); 93 } 94 95 // static 96 DownloadItemModelData* DownloadItemModelData::GetOrCreate( 97 DownloadItem* download) { 98 DownloadItemModelData* data = 99 static_cast<DownloadItemModelData*>(download->GetUserData(kKey)); 100 if (data == NULL) { 101 data = new DownloadItemModelData(); 102 download->SetUserData(kKey, data); 103 } 104 return data; 105 } 106 107 DownloadItemModelData::DownloadItemModelData() 108 : should_show_in_shelf_(true), 109 was_ui_notified_(false), 110 should_prefer_opening_in_browser_(false) { 111 } 112 113 base::string16 InterruptReasonStatusMessage(int reason) { 114 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 115 116 switch (static_cast<content::DownloadInterruptReason>(reason)) { 117 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED: 118 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED; 119 break; 120 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE: 121 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL; 122 break; 123 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG: 124 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG; 125 break; 126 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE: 127 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE; 128 break; 129 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED: 130 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS; 131 break; 132 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR: 133 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM; 134 break; 135 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED: 136 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED; 137 break; 138 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED: 139 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED; 140 break; 141 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT: 142 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT; 143 break; 144 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST: 145 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED: 146 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR; 147 break; 148 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT: 149 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT; 150 break; 151 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED: 152 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED; 153 break; 154 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN: 155 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN; 156 break; 157 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED: 158 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM; 159 break; 160 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT: 161 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE; 162 break; 163 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED: 164 string_id = IDS_DOWNLOAD_STATUS_CANCELLED; 165 break; 166 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN: 167 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN; 168 break; 169 case content::DOWNLOAD_INTERRUPT_REASON_CRASH: 170 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH; 171 break; 172 case content::DOWNLOAD_INTERRUPT_REASON_NONE: 173 NOTREACHED(); 174 // fallthrough 175 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: 176 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: 177 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED: 178 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 179 } 180 181 return l10n_util::GetStringUTF16(string_id); 182 } 183 184 base::string16 InterruptReasonMessage(int reason) { 185 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 186 base::string16 status_text; 187 188 switch (static_cast<content::DownloadInterruptReason>(reason)) { 189 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED: 190 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED; 191 break; 192 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE: 193 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL; 194 break; 195 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG: 196 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG; 197 break; 198 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE: 199 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE; 200 break; 201 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED: 202 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS; 203 break; 204 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR: 205 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM; 206 break; 207 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED: 208 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED; 209 break; 210 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED: 211 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED; 212 break; 213 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT: 214 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT; 215 break; 216 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST: 217 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED: 218 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR; 219 break; 220 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT: 221 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT; 222 break; 223 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED: 224 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED; 225 break; 226 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN: 227 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN; 228 break; 229 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED: 230 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM; 231 break; 232 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT: 233 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE; 234 break; 235 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED: 236 string_id = IDS_DOWNLOAD_STATUS_CANCELLED; 237 break; 238 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN: 239 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN; 240 break; 241 case content::DOWNLOAD_INTERRUPT_REASON_CRASH: 242 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH; 243 break; 244 case content::DOWNLOAD_INTERRUPT_REASON_NONE: 245 NOTREACHED(); 246 // fallthrough 247 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: 248 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: 249 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED: 250 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 251 } 252 253 status_text = l10n_util::GetStringUTF16(string_id); 254 255 return status_text; 256 } 257 258 } // namespace 259 260 // ----------------------------------------------------------------------------- 261 // DownloadItemModel 262 263 DownloadItemModel::DownloadItemModel(DownloadItem* download) 264 : download_(download) {} 265 266 DownloadItemModel::~DownloadItemModel() {} 267 268 base::string16 DownloadItemModel::GetInterruptReasonText() const { 269 if (download_->GetState() != DownloadItem::INTERRUPTED || 270 download_->GetLastReason() == 271 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) { 272 return base::string16(); 273 } 274 return InterruptReasonMessage(download_->GetLastReason()); 275 } 276 277 base::string16 DownloadItemModel::GetStatusText() const { 278 base::string16 status_text; 279 switch (download_->GetState()) { 280 case DownloadItem::IN_PROGRESS: 281 status_text = GetInProgressStatusString(); 282 break; 283 case DownloadItem::COMPLETE: 284 if (download_->GetFileExternallyRemoved()) { 285 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED); 286 } else { 287 status_text.clear(); 288 } 289 break; 290 case DownloadItem::CANCELLED: 291 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED); 292 break; 293 case DownloadItem::INTERRUPTED: { 294 content::DownloadInterruptReason reason = download_->GetLastReason(); 295 if (reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) { 296 base::string16 interrupt_reason = InterruptReasonStatusMessage(reason); 297 status_text = l10n_util::GetStringFUTF16( 298 IDS_DOWNLOAD_STATUS_INTERRUPTED, interrupt_reason); 299 } else { 300 // Same as DownloadItem::CANCELLED. 301 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED); 302 } 303 break; 304 } 305 default: 306 NOTREACHED(); 307 } 308 309 return status_text; 310 } 311 312 base::string16 DownloadItemModel::GetTabProgressStatusText() const { 313 int64 total = GetTotalBytes(); 314 int64 size = download_->GetReceivedBytes(); 315 base::string16 received_size = ui::FormatBytes(size); 316 base::string16 amount = received_size; 317 318 // Adjust both strings for the locale direction since we don't yet know which 319 // string we'll end up using for constructing the final progress string. 320 base::i18n::AdjustStringForLocaleDirection(&amount); 321 322 if (total) { 323 base::string16 total_text = ui::FormatBytes(total); 324 base::i18n::AdjustStringForLocaleDirection(&total_text); 325 326 base::i18n::AdjustStringForLocaleDirection(&received_size); 327 amount = l10n_util::GetStringFUTF16( 328 IDS_DOWNLOAD_TAB_PROGRESS_SIZE, received_size, total_text); 329 } else { 330 amount.assign(received_size); 331 } 332 int64 current_speed = download_->CurrentSpeed(); 333 base::string16 speed_text = ui::FormatSpeed(current_speed); 334 base::i18n::AdjustStringForLocaleDirection(&speed_text); 335 336 base::TimeDelta remaining; 337 base::string16 time_remaining; 338 if (download_->IsPaused()) { 339 time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED); 340 } else if (download_->TimeRemaining(&remaining)) { 341 time_remaining = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING, 342 ui::TimeFormat::LENGTH_SHORT, 343 remaining); 344 } 345 346 if (time_remaining.empty()) { 347 base::i18n::AdjustStringForLocaleDirection(&amount); 348 return l10n_util::GetStringFUTF16( 349 IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN, speed_text, amount); 350 } 351 return l10n_util::GetStringFUTF16( 352 IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text, amount, time_remaining); 353 } 354 355 base::string16 DownloadItemModel::GetTooltipText(const gfx::FontList& font_list, 356 int max_width) const { 357 base::string16 tooltip = gfx::ElideFilename( 358 download_->GetFileNameToReportUser(), font_list, max_width); 359 content::DownloadInterruptReason reason = download_->GetLastReason(); 360 if (download_->GetState() == DownloadItem::INTERRUPTED && 361 reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) { 362 tooltip += base::ASCIIToUTF16("\n"); 363 tooltip += gfx::ElideText(InterruptReasonStatusMessage(reason), 364 font_list, max_width, gfx::ELIDE_TAIL); 365 } 366 return tooltip; 367 } 368 369 base::string16 DownloadItemModel::GetWarningText(const gfx::FontList& font_list, 370 int base_width) const { 371 // Should only be called if IsDangerous(). 372 DCHECK(IsDangerous()); 373 base::string16 elided_filename = 374 gfx::ElideFilename(download_->GetFileNameToReportUser(), font_list, 375 base_width); 376 switch (download_->GetDangerType()) { 377 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: { 378 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); 379 } 380 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: { 381 if (download_crx_util::IsExtensionDownload(*download_)) { 382 return l10n_util::GetStringUTF16( 383 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION); 384 } else { 385 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, 386 elided_filename); 387 } 388 } 389 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 390 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 391 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, 392 elided_filename); 393 } 394 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { 395 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, 396 elided_filename); 397 } 398 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 399 return l10n_util::GetStringFUTF16( 400 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename); 401 } 402 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: 403 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: 404 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: 405 case content::DOWNLOAD_DANGER_TYPE_MAX: { 406 break; 407 } 408 } 409 NOTREACHED(); 410 return base::string16(); 411 } 412 413 base::string16 DownloadItemModel::GetWarningConfirmButtonText() const { 414 // Should only be called if IsDangerous() 415 DCHECK(IsDangerous()); 416 if (download_->GetDangerType() == 417 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE && 418 download_crx_util::IsExtensionDownload(*download_)) { 419 return l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD); 420 } else { 421 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD); 422 } 423 } 424 425 int64 DownloadItemModel::GetCompletedBytes() const { 426 return download_->GetReceivedBytes(); 427 } 428 429 int64 DownloadItemModel::GetTotalBytes() const { 430 return download_->AllDataSaved() ? download_->GetReceivedBytes() : 431 download_->GetTotalBytes(); 432 } 433 434 // TODO(asanka,rdsmith): Once 'open' moves exclusively to the 435 // ChromeDownloadManagerDelegate, we should calculate the percentage here 436 // instead of calling into the DownloadItem. 437 int DownloadItemModel::PercentComplete() const { 438 return download_->PercentComplete(); 439 } 440 441 bool DownloadItemModel::IsDangerous() const { 442 return download_->IsDangerous(); 443 } 444 445 bool DownloadItemModel::MightBeMalicious() const { 446 if (!IsDangerous()) 447 return false; 448 switch (download_->GetDangerType()) { 449 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 450 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 451 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: 452 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 453 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: 454 return true; 455 456 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: 457 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: 458 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: 459 case content::DOWNLOAD_DANGER_TYPE_MAX: 460 // We shouldn't get any of these due to the IsDangerous() test above. 461 NOTREACHED(); 462 // Fallthrough. 463 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: 464 return false; 465 } 466 NOTREACHED(); 467 return false; 468 } 469 470 // If you change this definition of malicious, also update 471 // DownloadManagerImpl::NonMaliciousInProgressCount. 472 bool DownloadItemModel::IsMalicious() const { 473 if (!MightBeMalicious()) 474 return false; 475 switch (download_->GetDangerType()) { 476 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 477 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 478 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 479 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: 480 return true; 481 482 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: 483 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: 484 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: 485 case content::DOWNLOAD_DANGER_TYPE_MAX: 486 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: 487 // We shouldn't get any of these due to the MightBeMalicious() test above. 488 NOTREACHED(); 489 // Fallthrough. 490 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: 491 return false; 492 } 493 NOTREACHED(); 494 return false; 495 } 496 497 bool DownloadItemModel::ShouldAllowDownloadFeedback() const { 498 #if defined(FULL_SAFE_BROWSING) 499 if (!IsDangerous()) 500 return false; 501 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload( 502 *download_); 503 #else 504 return false; 505 #endif 506 } 507 508 bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const { 509 switch (download_->GetState()) { 510 case DownloadItem::IN_PROGRESS: 511 // If the download is dangerous or malicious, we should display a warning 512 // on the shelf until the user accepts the download. 513 if (IsDangerous()) 514 return false; 515 516 // If the download is an extension, temporary, or will be opened 517 // automatically, then it should be removed from the shelf on completion. 518 // TODO(asanka): The logic for deciding opening behavior should be in a 519 // central location. http://crbug.com/167702 520 return (download_crx_util::IsExtensionDownload(*download_) || 521 download_->IsTemporary() || 522 download_->GetOpenWhenComplete() || 523 download_->ShouldOpenFileBasedOnExtension()); 524 525 case DownloadItem::COMPLETE: 526 // If the download completed, then rely on GetAutoOpened() to check for 527 // opening behavior. This should accurately reflect whether the download 528 // was successfully opened. Extensions, for example, may fail to open. 529 return download_->GetAutoOpened() || download_->IsTemporary(); 530 531 case DownloadItem::CANCELLED: 532 case DownloadItem::INTERRUPTED: 533 // Interrupted or cancelled downloads should remain on the shelf. 534 return false; 535 536 case DownloadItem::MAX_DOWNLOAD_STATE: 537 NOTREACHED(); 538 } 539 540 NOTREACHED(); 541 return false; 542 } 543 544 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const { 545 return !download_->IsSavePackageDownload() && 546 !download_crx_util::IsExtensionDownload(*download_); 547 } 548 549 bool DownloadItemModel::ShouldShowInShelf() const { 550 const DownloadItemModelData* data = DownloadItemModelData::Get(download_); 551 return !data || data->should_show_in_shelf(); 552 } 553 554 void DownloadItemModel::SetShouldShowInShelf(bool should_show) { 555 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_); 556 data->set_should_show_in_shelf(should_show); 557 } 558 559 bool DownloadItemModel::ShouldNotifyUI() const { 560 Profile* profile = 561 Profile::FromBrowserContext(download_->GetBrowserContext()); 562 DownloadService* download_service = 563 DownloadServiceFactory::GetForBrowserContext(profile); 564 DownloadHistory* download_history = 565 (download_service ? download_service->GetDownloadHistory() : NULL); 566 567 // The browser is only interested in new downloads. Ones that were restored 568 // from history are not displayed on the shelf. The downloads page 569 // independently listens for new downloads when it is active. Note that the UI 570 // will be notified of downloads even if they are not meant to be displayed on 571 // the shelf (i.e. ShouldShowInShelf() returns false). This is because: 572 // * The shelf isn't the only UI. E.g. on Android, the UI is the system 573 // DownloadManager. 574 // * There are other UI activities that need to be performed. E.g. if the 575 // download was initiated from a new tab, then that tab should be closed. 576 // 577 // TODO(asanka): If an interrupted download is restored from history and is 578 // resumed, then ideally the UI should be notified. 579 return !download_history || 580 !download_history->WasRestoredFromHistory(download_); 581 } 582 583 bool DownloadItemModel::WasUINotified() const { 584 const DownloadItemModelData* data = DownloadItemModelData::Get(download_); 585 return data && data->was_ui_notified(); 586 } 587 588 void DownloadItemModel::SetWasUINotified(bool was_ui_notified) { 589 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_); 590 data->set_was_ui_notified(was_ui_notified); 591 } 592 593 bool DownloadItemModel::ShouldPreferOpeningInBrowser() const { 594 const DownloadItemModelData* data = DownloadItemModelData::Get(download_); 595 return data && data->should_prefer_opening_in_browser(); 596 } 597 598 void DownloadItemModel::SetShouldPreferOpeningInBrowser(bool preference) { 599 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_); 600 data->set_should_prefer_opening_in_browser(preference); 601 } 602 603 base::string16 DownloadItemModel::GetProgressSizesString() const { 604 base::string16 size_ratio; 605 int64 size = GetCompletedBytes(); 606 int64 total = GetTotalBytes(); 607 if (total > 0) { 608 ui::DataUnits amount_units = ui::GetByteDisplayUnits(total); 609 base::string16 simple_size = ui::FormatBytesWithUnits(size, amount_units, false); 610 611 // In RTL locales, we render the text "size/total" in an RTL context. This 612 // is problematic since a string such as "123/456 MB" is displayed 613 // as "MB 123/456" because it ends with an LTR run. In order to solve this, 614 // we mark the total string as an LTR string if the UI layout is 615 // right-to-left so that the string "456 MB" is treated as an LTR run. 616 base::string16 simple_total = base::i18n::GetDisplayStringInLTRDirectionality( 617 ui::FormatBytesWithUnits(total, amount_units, true)); 618 size_ratio = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES, 619 simple_size, simple_total); 620 } else { 621 size_ratio = ui::FormatBytes(size); 622 } 623 return size_ratio; 624 } 625 626 base::string16 DownloadItemModel::GetInProgressStatusString() const { 627 DCHECK_EQ(DownloadItem::IN_PROGRESS, download_->GetState()); 628 629 TimeDelta time_remaining; 630 // time_remaining is only known if the download isn't paused. 631 bool time_remaining_known = (!download_->IsPaused() && 632 download_->TimeRemaining(&time_remaining)); 633 634 // Indication of progress. (E.g.:"100/200 MB" or "100MB") 635 base::string16 size_ratio = GetProgressSizesString(); 636 637 // The download is a CRX (app, extension, theme, ...) and it is being unpacked 638 // and validated. 639 if (download_->AllDataSaved() && 640 download_crx_util::IsExtensionDownload(*download_)) { 641 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING); 642 } 643 644 // A paused download: "100/120 MB, Paused" 645 if (download_->IsPaused()) { 646 return l10n_util::GetStringFUTF16( 647 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio, 648 l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED)); 649 } 650 651 // A download scheduled to be opened when complete: "Opening in 10 secs" 652 if (download_->GetOpenWhenComplete()) { 653 if (!time_remaining_known) 654 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE); 655 656 return l10n_util::GetStringFUTF16( 657 IDS_DOWNLOAD_STATUS_OPEN_IN, 658 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, 659 ui::TimeFormat::LENGTH_SHORT, time_remaining)); 660 } 661 662 // In progress download with known time left: "100/120 MB, 10 secs left" 663 if (time_remaining_known) { 664 return l10n_util::GetStringFUTF16( 665 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio, 666 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING, 667 ui::TimeFormat::LENGTH_SHORT, time_remaining)); 668 } 669 670 // In progress download with no known time left and non-zero completed bytes: 671 // "100/120 MB" or "100 MB" 672 if (GetCompletedBytes() > 0) 673 return size_ratio; 674 675 // Instead of displaying "0 B" we say "Starting..." 676 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING); 677 } 678 679 void DownloadItemModel::OpenUsingPlatformHandler() { 680 DownloadService* download_service = 681 DownloadServiceFactory::GetForBrowserContext( 682 download_->GetBrowserContext()); 683 if (!download_service) 684 return; 685 686 ChromeDownloadManagerDelegate* delegate = 687 download_service->GetDownloadManagerDelegate(); 688 if (!delegate) 689 return; 690 delegate->OpenDownloadUsingPlatformHandler(download_); 691 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM); 692 } 693