No dual_mode on Win10+ shortcuts.
[chromium-blink-merge.git] / chrome / browser / download / download_item_model.cc
blob6ef6de5f1759abdca7941983a4de2da622efc825
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.
5 #include "chrome/browser/download/download_item_model.h"
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"
33 using base::TimeDelta;
34 using content::DownloadItem;
36 namespace {
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);
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);
51 // Whether the download should be displayed in the download shelf. True by
52 // default.
53 bool should_show_in_shelf_;
55 // Whether the UI has been notified about this download.
56 bool was_ui_notified_;
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_;
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_;
66 // Whether the download is currently being revived.
67 bool is_being_revived_;
69 private:
70 DownloadItemModelData();
71 ~DownloadItemModelData() override {}
73 static const char kKey[];
76 // static
77 const char DownloadItemModelData::kKey[] = "DownloadItemModelData key";
79 // static
80 const DownloadItemModelData* DownloadItemModelData::Get(
81 const DownloadItem* download) {
82 return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey));
85 // static
86 DownloadItemModelData* DownloadItemModelData::GetOrCreate(
87 DownloadItem* download) {
88 DownloadItemModelData* data =
89 static_cast<DownloadItemModelData*>(download->GetUserData(kKey));
90 if (data == NULL) {
91 data = new DownloadItemModelData();
92 download->SetUserData(kKey, data);
94 return data;
97 DownloadItemModelData::DownloadItemModelData()
98 : should_show_in_shelf_(true),
99 was_ui_notified_(false),
100 should_prefer_opening_in_browser_(false),
101 is_dangerous_file_based_on_type_(false),
102 is_being_revived_(false) {
105 base::string16 InterruptReasonStatusMessage(int reason) {
106 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
108 switch (static_cast<content::DownloadInterruptReason>(reason)) {
109 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
110 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED;
111 break;
112 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
113 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL;
114 break;
115 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
116 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG;
117 break;
118 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
119 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE;
120 break;
121 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
122 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS;
123 break;
124 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
125 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM;
126 break;
127 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
128 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED;
129 break;
130 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
131 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED;
132 break;
133 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
134 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT;
135 break;
136 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
137 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
138 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR;
139 break;
140 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
141 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT;
142 break;
143 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
144 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED;
145 break;
146 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
147 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN;
148 break;
149 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
150 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM;
151 break;
152 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
153 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE;
154 break;
155 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
156 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
157 break;
158 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
159 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN;
160 break;
161 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
162 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH;
163 break;
164 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
165 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED;
166 break;
167 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
168 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM;
169 break;
170 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
171 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FORBIDDEN;
172 break;
173 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
174 NOTREACHED();
175 // fallthrough
176 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
177 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
178 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
179 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
182 return l10n_util::GetStringUTF16(string_id);
185 base::string16 InterruptReasonMessage(int reason) {
186 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
187 base::string16 status_text;
189 switch (static_cast<content::DownloadInterruptReason>(reason)) {
190 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
191 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED;
192 break;
193 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
194 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL;
195 break;
196 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
197 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG;
198 break;
199 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
200 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE;
201 break;
202 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
203 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS;
204 break;
205 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
206 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM;
207 break;
208 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
209 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED;
210 break;
211 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
212 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED;
213 break;
214 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
215 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT;
216 break;
217 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
218 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
219 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR;
220 break;
221 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
222 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT;
223 break;
224 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
225 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED;
226 break;
227 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
228 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN;
229 break;
230 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
231 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM;
232 break;
233 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
234 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE;
235 break;
236 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
237 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
238 break;
239 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
240 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN;
241 break;
242 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
243 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH;
244 break;
245 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
246 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED;
247 break;
248 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
249 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM;
250 break;
251 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
252 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FORBIDDEN;
253 break;
254 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
255 NOTREACHED();
256 // fallthrough
257 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
258 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION:
259 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
260 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
263 status_text = l10n_util::GetStringUTF16(string_id);
265 return status_text;
268 } // namespace
270 // -----------------------------------------------------------------------------
271 // DownloadItemModel
273 DownloadItemModel::DownloadItemModel(DownloadItem* download)
274 : download_(download) {}
276 DownloadItemModel::~DownloadItemModel() {}
278 base::string16 DownloadItemModel::GetInterruptReasonText() const {
279 if (download_->GetState() != DownloadItem::INTERRUPTED ||
280 download_->GetLastReason() ==
281 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
282 return base::string16();
284 return InterruptReasonMessage(download_->GetLastReason());
287 base::string16 DownloadItemModel::GetStatusText() const {
288 base::string16 status_text;
289 switch (download_->GetState()) {
290 case DownloadItem::IN_PROGRESS:
291 status_text = GetInProgressStatusString();
292 break;
293 case DownloadItem::COMPLETE:
294 if (download_->GetFileExternallyRemoved()) {
295 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED);
296 } else {
297 status_text.clear();
299 break;
300 case DownloadItem::CANCELLED:
301 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
302 break;
303 case DownloadItem::INTERRUPTED: {
304 content::DownloadInterruptReason reason = download_->GetLastReason();
305 if (reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
306 base::string16 interrupt_reason = InterruptReasonStatusMessage(reason);
307 status_text = l10n_util::GetStringFUTF16(
308 IDS_DOWNLOAD_STATUS_INTERRUPTED, interrupt_reason);
309 } else {
310 // Same as DownloadItem::CANCELLED.
311 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
313 break;
315 default:
316 NOTREACHED();
319 return status_text;
322 base::string16 DownloadItemModel::GetTabProgressStatusText() const {
323 int64 total = GetTotalBytes();
324 int64 size = download_->GetReceivedBytes();
325 base::string16 received_size = ui::FormatBytes(size);
326 base::string16 amount = received_size;
328 // Adjust both strings for the locale direction since we don't yet know which
329 // string we'll end up using for constructing the final progress string.
330 base::i18n::AdjustStringForLocaleDirection(&amount);
332 if (total) {
333 base::string16 total_text = ui::FormatBytes(total);
334 base::i18n::AdjustStringForLocaleDirection(&total_text);
336 base::i18n::AdjustStringForLocaleDirection(&received_size);
337 amount = l10n_util::GetStringFUTF16(
338 IDS_DOWNLOAD_TAB_PROGRESS_SIZE, received_size, total_text);
339 } else {
340 amount.assign(received_size);
342 int64 current_speed = download_->CurrentSpeed();
343 base::string16 speed_text = ui::FormatSpeed(current_speed);
344 base::i18n::AdjustStringForLocaleDirection(&speed_text);
346 base::TimeDelta remaining;
347 base::string16 time_remaining;
348 if (download_->IsPaused()) {
349 time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
350 } else if (download_->TimeRemaining(&remaining)) {
351 time_remaining = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
352 ui::TimeFormat::LENGTH_SHORT,
353 remaining);
356 if (time_remaining.empty()) {
357 base::i18n::AdjustStringForLocaleDirection(&amount);
358 return l10n_util::GetStringFUTF16(
359 IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN, speed_text, amount);
361 return l10n_util::GetStringFUTF16(
362 IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text, amount, time_remaining);
365 base::string16 DownloadItemModel::GetTooltipText(const gfx::FontList& font_list,
366 int max_width) const {
367 base::string16 tooltip = gfx::ElideFilename(
368 download_->GetFileNameToReportUser(), font_list, max_width);
369 content::DownloadInterruptReason reason = download_->GetLastReason();
370 if (download_->GetState() == DownloadItem::INTERRUPTED &&
371 reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
372 tooltip += base::ASCIIToUTF16("\n");
373 tooltip += gfx::ElideText(InterruptReasonStatusMessage(reason),
374 font_list, max_width, gfx::ELIDE_TAIL);
376 return tooltip;
379 base::string16 DownloadItemModel::GetWarningText(const gfx::FontList& font_list,
380 int base_width) const {
381 // Should only be called if IsDangerous().
382 DCHECK(IsDangerous());
383 base::string16 elided_filename =
384 gfx::ElideFilename(download_->GetFileNameToReportUser(), font_list,
385 base_width);
386 switch (download_->GetDangerType()) {
387 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
388 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
390 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
391 if (download_crx_util::IsExtensionDownload(*download_)) {
392 return l10n_util::GetStringUTF16(
393 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
394 } else {
395 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
396 elided_filename);
399 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
400 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
401 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
402 elided_filename);
404 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
405 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
406 elided_filename);
408 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
409 return l10n_util::GetStringFUTF16(
410 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename);
412 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
413 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
414 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
415 case content::DOWNLOAD_DANGER_TYPE_MAX: {
416 break;
419 NOTREACHED();
420 return base::string16();
423 base::string16 DownloadItemModel::GetWarningConfirmButtonText() const {
424 // Should only be called if IsDangerous()
425 DCHECK(IsDangerous());
426 if (download_->GetDangerType() ==
427 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE &&
428 download_crx_util::IsExtensionDownload(*download_)) {
429 return l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD);
430 } else {
431 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
435 int64 DownloadItemModel::GetCompletedBytes() const {
436 return download_->GetReceivedBytes();
439 int64 DownloadItemModel::GetTotalBytes() const {
440 return download_->AllDataSaved() ? download_->GetReceivedBytes() :
441 download_->GetTotalBytes();
444 // TODO(asanka,rdsmith): Once 'open' moves exclusively to the
445 // ChromeDownloadManagerDelegate, we should calculate the percentage here
446 // instead of calling into the DownloadItem.
447 int DownloadItemModel::PercentComplete() const {
448 return download_->PercentComplete();
451 bool DownloadItemModel::IsDangerous() const {
452 return download_->IsDangerous();
455 bool DownloadItemModel::MightBeMalicious() const {
456 if (!IsDangerous())
457 return false;
458 switch (download_->GetDangerType()) {
459 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
460 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
461 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
462 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
463 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
464 return true;
466 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
467 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
468 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
469 case content::DOWNLOAD_DANGER_TYPE_MAX:
470 // We shouldn't get any of these due to the IsDangerous() test above.
471 NOTREACHED();
472 // Fallthrough.
473 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
474 return false;
476 NOTREACHED();
477 return false;
480 // If you change this definition of malicious, also update
481 // DownloadManagerImpl::NonMaliciousInProgressCount.
482 bool DownloadItemModel::IsMalicious() const {
483 if (!MightBeMalicious())
484 return false;
485 switch (download_->GetDangerType()) {
486 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
487 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
488 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
489 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
490 return true;
492 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
493 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
494 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
495 case content::DOWNLOAD_DANGER_TYPE_MAX:
496 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
497 // We shouldn't get any of these due to the MightBeMalicious() test above.
498 NOTREACHED();
499 // Fallthrough.
500 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
501 return false;
503 NOTREACHED();
504 return false;
507 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
508 #if defined(FULL_SAFE_BROWSING)
509 if (!IsDangerous())
510 return false;
511 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
512 *download_);
513 #else
514 return false;
515 #endif
518 bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const {
519 switch (download_->GetState()) {
520 case DownloadItem::IN_PROGRESS:
521 // If the download is dangerous or malicious, we should display a warning
522 // on the shelf until the user accepts the download.
523 if (IsDangerous())
524 return false;
526 // If the download is an extension, temporary, or will be opened
527 // automatically, then it should be removed from the shelf on completion.
528 // TODO(asanka): The logic for deciding opening behavior should be in a
529 // central location. http://crbug.com/167702
530 return (download_crx_util::IsExtensionDownload(*download_) ||
531 download_->IsTemporary() ||
532 download_->GetOpenWhenComplete() ||
533 download_->ShouldOpenFileBasedOnExtension());
535 case DownloadItem::COMPLETE:
536 // If the download completed, then rely on GetAutoOpened() to check for
537 // opening behavior. This should accurately reflect whether the download
538 // was successfully opened. Extensions, for example, may fail to open.
539 return download_->GetAutoOpened() || download_->IsTemporary();
541 case DownloadItem::CANCELLED:
542 case DownloadItem::INTERRUPTED:
543 // Interrupted or cancelled downloads should remain on the shelf.
544 return false;
546 case DownloadItem::MAX_DOWNLOAD_STATE:
547 NOTREACHED();
550 NOTREACHED();
551 return false;
554 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
555 return !download_->IsSavePackageDownload() &&
556 !download_crx_util::IsExtensionDownload(*download_);
559 bool DownloadItemModel::ShouldShowInShelf() const {
560 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
561 return !data || data->should_show_in_shelf_;
564 void DownloadItemModel::SetShouldShowInShelf(bool should_show) {
565 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
566 data->should_show_in_shelf_ = should_show;
569 bool DownloadItemModel::ShouldNotifyUI() const {
570 Profile* profile =
571 Profile::FromBrowserContext(download_->GetBrowserContext());
572 DownloadService* download_service =
573 DownloadServiceFactory::GetForBrowserContext(profile);
574 DownloadHistory* download_history =
575 (download_service ? download_service->GetDownloadHistory() : NULL);
577 // The browser is only interested in new downloads. Ones that were restored
578 // from history are not displayed on the shelf. The downloads page
579 // independently listens for new downloads when it is active. Note that the UI
580 // will be notified of downloads even if they are not meant to be displayed on
581 // the shelf (i.e. ShouldShowInShelf() returns false). This is because:
582 // * The shelf isn't the only UI. E.g. on Android, the UI is the system
583 // DownloadManager.
584 // * There are other UI activities that need to be performed. E.g. if the
585 // download was initiated from a new tab, then that tab should be closed.
587 // TODO(asanka): If an interrupted download is restored from history and is
588 // resumed, then ideally the UI should be notified.
589 return !download_history ||
590 !download_history->WasRestoredFromHistory(download_);
593 bool DownloadItemModel::WasUINotified() const {
594 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
595 return data && data->was_ui_notified_;
598 void DownloadItemModel::SetWasUINotified(bool was_ui_notified) {
599 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
600 data->was_ui_notified_ = was_ui_notified;
603 bool DownloadItemModel::ShouldPreferOpeningInBrowser() const {
604 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
605 return data && data->should_prefer_opening_in_browser_;
608 void DownloadItemModel::SetShouldPreferOpeningInBrowser(bool preference) {
609 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
610 data->should_prefer_opening_in_browser_ = preference;
613 bool DownloadItemModel::IsDangerousFileBasedOnType() const {
614 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
615 return data && data->is_dangerous_file_based_on_type_;
618 void DownloadItemModel::SetIsDangerousFileBasedOnType(bool dangerous) {
619 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
620 data->is_dangerous_file_based_on_type_ = dangerous;
623 bool DownloadItemModel::IsBeingRevived() const {
624 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
625 return data && data->is_being_revived_;
628 void DownloadItemModel::SetIsBeingRevived(bool is_being_revived) {
629 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
630 data->is_being_revived_ = is_being_revived;
633 base::string16 DownloadItemModel::GetProgressSizesString() const {
634 base::string16 size_ratio;
635 int64 size = GetCompletedBytes();
636 int64 total = GetTotalBytes();
637 if (total > 0) {
638 ui::DataUnits amount_units = ui::GetByteDisplayUnits(total);
639 base::string16 simple_size = ui::FormatBytesWithUnits(size, amount_units, false);
641 // In RTL locales, we render the text "size/total" in an RTL context. This
642 // is problematic since a string such as "123/456 MB" is displayed
643 // as "MB 123/456" because it ends with an LTR run. In order to solve this,
644 // we mark the total string as an LTR string if the UI layout is
645 // right-to-left so that the string "456 MB" is treated as an LTR run.
646 base::string16 simple_total = base::i18n::GetDisplayStringInLTRDirectionality(
647 ui::FormatBytesWithUnits(total, amount_units, true));
648 size_ratio = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES,
649 simple_size, simple_total);
650 } else {
651 size_ratio = ui::FormatBytes(size);
653 return size_ratio;
656 base::string16 DownloadItemModel::GetInProgressStatusString() const {
657 DCHECK_EQ(DownloadItem::IN_PROGRESS, download_->GetState());
659 TimeDelta time_remaining;
660 // time_remaining is only known if the download isn't paused.
661 bool time_remaining_known = (!download_->IsPaused() &&
662 download_->TimeRemaining(&time_remaining));
664 // Indication of progress. (E.g.:"100/200 MB" or "100MB")
665 base::string16 size_ratio = GetProgressSizesString();
667 // The download is a CRX (app, extension, theme, ...) and it is being unpacked
668 // and validated.
669 if (download_->AllDataSaved() &&
670 download_crx_util::IsExtensionDownload(*download_)) {
671 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING);
674 // A paused download: "100/120 MB, Paused"
675 if (download_->IsPaused()) {
676 return l10n_util::GetStringFUTF16(
677 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio,
678 l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED));
681 // A download scheduled to be opened when complete: "Opening in 10 secs"
682 if (download_->GetOpenWhenComplete()) {
683 if (!time_remaining_known)
684 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE);
686 return l10n_util::GetStringFUTF16(
687 IDS_DOWNLOAD_STATUS_OPEN_IN,
688 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
689 ui::TimeFormat::LENGTH_SHORT, time_remaining));
692 // In progress download with known time left: "100/120 MB, 10 secs left"
693 if (time_remaining_known) {
694 return l10n_util::GetStringFUTF16(
695 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio,
696 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
697 ui::TimeFormat::LENGTH_SHORT, time_remaining));
700 // In progress download with no known time left and non-zero completed bytes:
701 // "100/120 MB" or "100 MB"
702 if (GetCompletedBytes() > 0)
703 return size_ratio;
705 // Instead of displaying "0 B" we say "Starting..."
706 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING);
709 void DownloadItemModel::OpenUsingPlatformHandler() {
710 DownloadService* download_service =
711 DownloadServiceFactory::GetForBrowserContext(
712 download_->GetBrowserContext());
713 if (!download_service)
714 return;
716 ChromeDownloadManagerDelegate* delegate =
717 download_service->GetDownloadManagerDelegate();
718 if (!delegate)
719 return;
720 delegate->OpenDownloadUsingPlatformHandler(download_);
721 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM);