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 "chrome/grit/chromium_strings.h" 24 #include "chrome/grit/generated_resources.h" 25 #include "content/public/browser/download_danger_type.h" 26 #include "content/public/browser/download_interrupt_reasons.h" 27 #include "content/public/browser/download_item.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 // Whether the download should be displayed in the download shelf. True by 52 // default. 53 bool should_show_in_shelf_; 54 55 // Whether the UI has been notified about this download. 56 bool was_ui_notified_; 57 58 // Whether the download should be opened in the browser vs. the system handler 59 // for the file type. 60 bool should_prefer_opening_in_browser_; 61 62 // Whether the download should be considered dangerous if SafeBrowsing doesn't 63 // come up with a verdict. 64 bool is_dangerous_file_based_on_type_; 65 66 private: 67 DownloadItemModelData(); 68 virtual ~DownloadItemModelData() {} 69 70 static const char kKey[]; 71 }; 72 73 // static 74 const char DownloadItemModelData::kKey[] = "DownloadItemModelData key"; 75 76 // static 77 const DownloadItemModelData* DownloadItemModelData::Get( 78 const DownloadItem* download) { 79 return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey)); 80 } 81 82 // static 83 DownloadItemModelData* DownloadItemModelData::GetOrCreate( 84 DownloadItem* download) { 85 DownloadItemModelData* data = 86 static_cast<DownloadItemModelData*>(download->GetUserData(kKey)); 87 if (data == NULL) { 88 data = new DownloadItemModelData(); 89 download->SetUserData(kKey, data); 90 } 91 return data; 92 } 93 94 DownloadItemModelData::DownloadItemModelData() 95 : should_show_in_shelf_(true), 96 was_ui_notified_(false), 97 should_prefer_opening_in_browser_(false), 98 is_dangerous_file_based_on_type_(false) { 99 } 100 101 base::string16 InterruptReasonStatusMessage(int reason) { 102 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 103 104 switch (static_cast<content::DownloadInterruptReason>(reason)) { 105 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED: 106 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED; 107 break; 108 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE: 109 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL; 110 break; 111 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG: 112 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG; 113 break; 114 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE: 115 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE; 116 break; 117 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED: 118 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS; 119 break; 120 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR: 121 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM; 122 break; 123 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED: 124 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED; 125 break; 126 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED: 127 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED; 128 break; 129 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT: 130 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT; 131 break; 132 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST: 133 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED: 134 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR; 135 break; 136 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT: 137 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT; 138 break; 139 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED: 140 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED; 141 break; 142 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN: 143 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN; 144 break; 145 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED: 146 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM; 147 break; 148 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT: 149 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE; 150 break; 151 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED: 152 string_id = IDS_DOWNLOAD_STATUS_CANCELLED; 153 break; 154 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN: 155 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN; 156 break; 157 case content::DOWNLOAD_INTERRUPT_REASON_CRASH: 158 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH; 159 break; 160 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED: 161 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED; 162 break; 163 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM: 164 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM; 165 break; 166 case content::DOWNLOAD_INTERRUPT_REASON_NONE: 167 NOTREACHED(); 168 // fallthrough 169 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: 170 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: 171 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED: 172 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 173 } 174 175 return l10n_util::GetStringUTF16(string_id); 176 } 177 178 base::string16 InterruptReasonMessage(int reason) { 179 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; 180 base::string16 status_text; 181 182 switch (static_cast<content::DownloadInterruptReason>(reason)) { 183 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED: 184 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED; 185 break; 186 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE: 187 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL; 188 break; 189 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG: 190 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG; 191 break; 192 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE: 193 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE; 194 break; 195 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED: 196 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS; 197 break; 198 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR: 199 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM; 200 break; 201 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED: 202 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED; 203 break; 204 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED: 205 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED; 206 break; 207 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT: 208 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT; 209 break; 210 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST: 211 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED: 212 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR; 213 break; 214 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT: 215 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT; 216 break; 217 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED: 218 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED; 219 break; 220 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN: 221 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN; 222 break; 223 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED: 224 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM; 225 break; 226 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT: 227 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE; 228 break; 229 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED: 230 string_id = IDS_DOWNLOAD_STATUS_CANCELLED; 231 break; 232 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN: 233 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN; 234 break; 235 case content::DOWNLOAD_INTERRUPT_REASON_CRASH: 236 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH; 237 break; 238 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED: 239 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED; 240 break; 241 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM: 242 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM; 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->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->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->should_prefer_opening_in_browser_ = preference; 601 } 602 603 bool DownloadItemModel::IsDangerousFileBasedOnType() const { 604 const DownloadItemModelData* data = DownloadItemModelData::Get(download_); 605 return data && data->is_dangerous_file_based_on_type_; 606 } 607 608 void DownloadItemModel::SetIsDangerousFileBasedOnType(bool dangerous) { 609 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_); 610 data->is_dangerous_file_based_on_type_ = dangerous; 611 } 612 613 base::string16 DownloadItemModel::GetProgressSizesString() const { 614 base::string16 size_ratio; 615 int64 size = GetCompletedBytes(); 616 int64 total = GetTotalBytes(); 617 if (total > 0) { 618 ui::DataUnits amount_units = ui::GetByteDisplayUnits(total); 619 base::string16 simple_size = ui::FormatBytesWithUnits(size, amount_units, false); 620 621 // In RTL locales, we render the text "size/total" in an RTL context. This 622 // is problematic since a string such as "123/456 MB" is displayed 623 // as "MB 123/456" because it ends with an LTR run. In order to solve this, 624 // we mark the total string as an LTR string if the UI layout is 625 // right-to-left so that the string "456 MB" is treated as an LTR run. 626 base::string16 simple_total = base::i18n::GetDisplayStringInLTRDirectionality( 627 ui::FormatBytesWithUnits(total, amount_units, true)); 628 size_ratio = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES, 629 simple_size, simple_total); 630 } else { 631 size_ratio = ui::FormatBytes(size); 632 } 633 return size_ratio; 634 } 635 636 base::string16 DownloadItemModel::GetInProgressStatusString() const { 637 DCHECK_EQ(DownloadItem::IN_PROGRESS, download_->GetState()); 638 639 TimeDelta time_remaining; 640 // time_remaining is only known if the download isn't paused. 641 bool time_remaining_known = (!download_->IsPaused() && 642 download_->TimeRemaining(&time_remaining)); 643 644 // Indication of progress. (E.g.:"100/200 MB" or "100MB") 645 base::string16 size_ratio = GetProgressSizesString(); 646 647 // The download is a CRX (app, extension, theme, ...) and it is being unpacked 648 // and validated. 649 if (download_->AllDataSaved() && 650 download_crx_util::IsExtensionDownload(*download_)) { 651 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING); 652 } 653 654 // A paused download: "100/120 MB, Paused" 655 if (download_->IsPaused()) { 656 return l10n_util::GetStringFUTF16( 657 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio, 658 l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED)); 659 } 660 661 // A download scheduled to be opened when complete: "Opening in 10 secs" 662 if (download_->GetOpenWhenComplete()) { 663 if (!time_remaining_known) 664 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE); 665 666 return l10n_util::GetStringFUTF16( 667 IDS_DOWNLOAD_STATUS_OPEN_IN, 668 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, 669 ui::TimeFormat::LENGTH_SHORT, time_remaining)); 670 } 671 672 // In progress download with known time left: "100/120 MB, 10 secs left" 673 if (time_remaining_known) { 674 return l10n_util::GetStringFUTF16( 675 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio, 676 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING, 677 ui::TimeFormat::LENGTH_SHORT, time_remaining)); 678 } 679 680 // In progress download with no known time left and non-zero completed bytes: 681 // "100/120 MB" or "100 MB" 682 if (GetCompletedBytes() > 0) 683 return size_ratio; 684 685 // Instead of displaying "0 B" we say "Starting..." 686 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING); 687 } 688 689 void DownloadItemModel::OpenUsingPlatformHandler() { 690 DownloadService* download_service = 691 DownloadServiceFactory::GetForBrowserContext( 692 download_->GetBrowserContext()); 693 if (!download_service) 694 return; 695 696 ChromeDownloadManagerDelegate* delegate = 697 download_service->GetDownloadManagerDelegate(); 698 if (!delegate) 699 return; 700 delegate->OpenDownloadUsingPlatformHandler(download_); 701 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM); 702 } 703