Home | History | Annotate | Download | only in download
      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