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
;
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
{
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
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
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_
;
70 DownloadItemModelData();
71 ~DownloadItemModelData() override
{}
73 static const char kKey
[];
77 const char DownloadItemModelData::kKey
[] = "DownloadItemModelData key";
80 const DownloadItemModelData
* DownloadItemModelData::Get(
81 const DownloadItem
* download
) {
82 return static_cast<const DownloadItemModelData
*>(download
->GetUserData(kKey
));
86 DownloadItemModelData
* DownloadItemModelData::GetOrCreate(
87 DownloadItem
* download
) {
88 DownloadItemModelData
* data
=
89 static_cast<DownloadItemModelData
*>(download
->GetUserData(kKey
));
91 data
= new DownloadItemModelData();
92 download
->SetUserData(kKey
, 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
;
112 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
:
113 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL
;
115 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG
:
116 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG
;
118 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE
:
119 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE
;
121 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED
:
122 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS
;
124 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR
:
125 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM
;
127 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED
:
128 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED
;
130 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED
:
131 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED
;
133 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT
:
134 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT
;
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
;
140 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT
:
141 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT
;
143 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED
:
144 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED
;
146 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN
:
147 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN
;
149 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED
:
150 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM
;
152 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT
:
153 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE
;
155 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
:
156 string_id
= IDS_DOWNLOAD_STATUS_CANCELLED
;
158 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN
:
159 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN
;
161 case content::DOWNLOAD_INTERRUPT_REASON_CRASH
:
162 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH
;
164 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED
:
165 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED
;
167 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM
:
168 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM
;
170 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN
:
171 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FORBIDDEN
;
173 case content::DOWNLOAD_INTERRUPT_REASON_NONE
:
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
;
193 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
:
194 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL
;
196 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG
:
197 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG
;
199 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE
:
200 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE
;
202 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED
:
203 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS
;
205 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR
:
206 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM
;
208 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED
:
209 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED
;
211 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED
:
212 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED
;
214 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT
:
215 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT
;
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
;
221 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT
:
222 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT
;
224 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED
:
225 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED
;
227 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN
:
228 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN
;
230 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED
:
231 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM
;
233 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT
:
234 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE
;
236 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
:
237 string_id
= IDS_DOWNLOAD_STATUS_CANCELLED
;
239 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN
:
240 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN
;
242 case content::DOWNLOAD_INTERRUPT_REASON_CRASH
:
243 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH
;
245 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED
:
246 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED
;
248 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM
:
249 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM
;
251 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN
:
252 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FORBIDDEN
;
254 case content::DOWNLOAD_INTERRUPT_REASON_NONE
:
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
);
270 // -----------------------------------------------------------------------------
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();
293 case DownloadItem::COMPLETE
:
294 if (download_
->GetFileExternallyRemoved()) {
295 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED
);
300 case DownloadItem::CANCELLED
:
301 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED
);
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
);
310 // Same as DownloadItem::CANCELLED.
311 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED
);
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
);
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
);
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
,
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
);
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
,
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
);
395 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD
,
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
,
404 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
: {
405 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT
,
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
: {
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
);
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 {
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
:
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.
473 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
480 // If you change this definition of malicious, also update
481 // DownloadManagerImpl::NonMaliciousInProgressCount.
482 bool DownloadItemModel::IsMalicious() const {
483 if (!MightBeMalicious())
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
:
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.
500 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
507 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
508 #if defined(FULL_SAFE_BROWSING)
511 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
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.
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.
546 case DownloadItem::MAX_DOWNLOAD_STATE
:
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 {
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
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();
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
);
651 size_ratio
= ui::FormatBytes(size
);
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
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)
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
)
716 ChromeDownloadManagerDelegate
* delegate
=
717 download_service
->GetDownloadManagerDelegate();
720 delegate
->OpenDownloadUsingPlatformHandler(download_
);
721 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM
);