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 bool should_show_in_shelf() const { return should_show_in_shelf_
; }
52 void set_should_show_in_shelf(bool should_show_in_shelf
) {
53 should_show_in_shelf_
= should_show_in_shelf
;
56 bool was_ui_notified() const { return was_ui_notified_
; }
57 void set_was_ui_notified(bool was_ui_notified
) {
58 was_ui_notified_
= was_ui_notified
;
61 bool should_prefer_opening_in_browser() const {
62 return should_prefer_opening_in_browser_
;
64 void set_should_prefer_opening_in_browser(bool preference
) {
65 should_prefer_opening_in_browser_
= preference
;
69 DownloadItemModelData();
70 virtual ~DownloadItemModelData() {}
72 static const char kKey
[];
74 // Whether the download should be displayed in the download shelf. True by
76 bool should_show_in_shelf_
;
78 // Whether the UI has been notified about this download.
79 bool was_ui_notified_
;
81 // Whether the download should be opened in the browser vs. the system handler
83 bool should_prefer_opening_in_browser_
;
87 const char DownloadItemModelData::kKey
[] = "DownloadItemModelData key";
90 const DownloadItemModelData
* DownloadItemModelData::Get(
91 const DownloadItem
* download
) {
92 return static_cast<const DownloadItemModelData
*>(download
->GetUserData(kKey
));
96 DownloadItemModelData
* DownloadItemModelData::GetOrCreate(
97 DownloadItem
* download
) {
98 DownloadItemModelData
* data
=
99 static_cast<DownloadItemModelData
*>(download
->GetUserData(kKey
));
101 data
= new DownloadItemModelData();
102 download
->SetUserData(kKey
, data
);
107 DownloadItemModelData::DownloadItemModelData()
108 : should_show_in_shelf_(true),
109 was_ui_notified_(false),
110 should_prefer_opening_in_browser_(false) {
113 base::string16
InterruptReasonStatusMessage(int reason
) {
114 int string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
116 switch (static_cast<content::DownloadInterruptReason
>(reason
)) {
117 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED
:
118 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED
;
120 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
:
121 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL
;
123 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG
:
124 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG
;
126 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE
:
127 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE
;
129 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED
:
130 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS
;
132 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR
:
133 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM
;
135 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED
:
136 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED
;
138 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED
:
139 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED
;
141 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT
:
142 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT
;
144 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST
:
145 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
:
146 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR
;
148 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT
:
149 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT
;
151 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED
:
152 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED
;
154 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN
:
155 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN
;
157 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED
:
158 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM
;
160 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT
:
161 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE
;
163 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
:
164 string_id
= IDS_DOWNLOAD_STATUS_CANCELLED
;
166 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN
:
167 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN
;
169 case content::DOWNLOAD_INTERRUPT_REASON_CRASH
:
170 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH
;
172 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED
:
173 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED
;
175 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM
:
176 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM
;
178 case content::DOWNLOAD_INTERRUPT_REASON_NONE
:
181 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE
:
182 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION
:
183 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED
:
184 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
187 return l10n_util::GetStringUTF16(string_id
);
190 base::string16
InterruptReasonMessage(int reason
) {
191 int string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
192 base::string16 status_text
;
194 switch (static_cast<content::DownloadInterruptReason
>(reason
)) {
195 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED
:
196 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED
;
198 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
:
199 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL
;
201 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG
:
202 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG
;
204 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE
:
205 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE
;
207 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED
:
208 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS
;
210 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR
:
211 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM
;
213 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED
:
214 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED
;
216 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED
:
217 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED
;
219 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT
:
220 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT
;
222 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST
:
223 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
:
224 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR
;
226 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT
:
227 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT
;
229 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED
:
230 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED
;
232 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN
:
233 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN
;
235 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED
:
236 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM
;
238 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT
:
239 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE
;
241 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
:
242 string_id
= IDS_DOWNLOAD_STATUS_CANCELLED
;
244 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN
:
245 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN
;
247 case content::DOWNLOAD_INTERRUPT_REASON_CRASH
:
248 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH
;
250 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED
:
251 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED
;
253 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM
:
254 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM
;
256 case content::DOWNLOAD_INTERRUPT_REASON_NONE
:
259 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE
:
260 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION
:
261 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED
:
262 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
265 status_text
= l10n_util::GetStringUTF16(string_id
);
272 // -----------------------------------------------------------------------------
275 DownloadItemModel::DownloadItemModel(DownloadItem
* download
)
276 : download_(download
) {}
278 DownloadItemModel::~DownloadItemModel() {}
280 base::string16
DownloadItemModel::GetInterruptReasonText() const {
281 if (download_
->GetState() != DownloadItem::INTERRUPTED
||
282 download_
->GetLastReason() ==
283 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
) {
284 return base::string16();
286 return InterruptReasonMessage(download_
->GetLastReason());
289 base::string16
DownloadItemModel::GetStatusText() const {
290 base::string16 status_text
;
291 switch (download_
->GetState()) {
292 case DownloadItem::IN_PROGRESS
:
293 status_text
= GetInProgressStatusString();
295 case DownloadItem::COMPLETE
:
296 if (download_
->GetFileExternallyRemoved()) {
297 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED
);
302 case DownloadItem::CANCELLED
:
303 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED
);
305 case DownloadItem::INTERRUPTED
: {
306 content::DownloadInterruptReason reason
= download_
->GetLastReason();
307 if (reason
!= content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
) {
308 base::string16 interrupt_reason
= InterruptReasonStatusMessage(reason
);
309 status_text
= l10n_util::GetStringFUTF16(
310 IDS_DOWNLOAD_STATUS_INTERRUPTED
, interrupt_reason
);
312 // Same as DownloadItem::CANCELLED.
313 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED
);
324 base::string16
DownloadItemModel::GetTabProgressStatusText() const {
325 int64 total
= GetTotalBytes();
326 int64 size
= download_
->GetReceivedBytes();
327 base::string16 received_size
= ui::FormatBytes(size
);
328 base::string16 amount
= received_size
;
330 // Adjust both strings for the locale direction since we don't yet know which
331 // string we'll end up using for constructing the final progress string.
332 base::i18n::AdjustStringForLocaleDirection(&amount
);
335 base::string16 total_text
= ui::FormatBytes(total
);
336 base::i18n::AdjustStringForLocaleDirection(&total_text
);
338 base::i18n::AdjustStringForLocaleDirection(&received_size
);
339 amount
= l10n_util::GetStringFUTF16(
340 IDS_DOWNLOAD_TAB_PROGRESS_SIZE
, received_size
, total_text
);
342 amount
.assign(received_size
);
344 int64 current_speed
= download_
->CurrentSpeed();
345 base::string16 speed_text
= ui::FormatSpeed(current_speed
);
346 base::i18n::AdjustStringForLocaleDirection(&speed_text
);
348 base::TimeDelta remaining
;
349 base::string16 time_remaining
;
350 if (download_
->IsPaused()) {
351 time_remaining
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED
);
352 } else if (download_
->TimeRemaining(&remaining
)) {
353 time_remaining
= ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING
,
354 ui::TimeFormat::LENGTH_SHORT
,
358 if (time_remaining
.empty()) {
359 base::i18n::AdjustStringForLocaleDirection(&amount
);
360 return l10n_util::GetStringFUTF16(
361 IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN
, speed_text
, amount
);
363 return l10n_util::GetStringFUTF16(
364 IDS_DOWNLOAD_TAB_PROGRESS_STATUS
, speed_text
, amount
, time_remaining
);
367 base::string16
DownloadItemModel::GetTooltipText(const gfx::FontList
& font_list
,
368 int max_width
) const {
369 base::string16 tooltip
= gfx::ElideFilename(
370 download_
->GetFileNameToReportUser(), font_list
, max_width
);
371 content::DownloadInterruptReason reason
= download_
->GetLastReason();
372 if (download_
->GetState() == DownloadItem::INTERRUPTED
&&
373 reason
!= content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
) {
374 tooltip
+= base::ASCIIToUTF16("\n");
375 tooltip
+= gfx::ElideText(InterruptReasonStatusMessage(reason
),
376 font_list
, max_width
, gfx::ELIDE_TAIL
);
381 base::string16
DownloadItemModel::GetWarningText(const gfx::FontList
& font_list
,
382 int base_width
) const {
383 // Should only be called if IsDangerous().
384 DCHECK(IsDangerous());
385 base::string16 elided_filename
=
386 gfx::ElideFilename(download_
->GetFileNameToReportUser(), font_list
,
388 switch (download_
->GetDangerType()) {
389 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
: {
390 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL
);
392 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
: {
393 if (download_crx_util::IsExtensionDownload(*download_
)) {
394 return l10n_util::GetStringUTF16(
395 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION
);
397 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD
,
401 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
402 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
: {
403 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT
,
406 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
: {
407 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT
,
410 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
: {
411 return l10n_util::GetStringFUTF16(
412 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS
, elided_filename
);
414 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
415 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
416 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
417 case content::DOWNLOAD_DANGER_TYPE_MAX
: {
422 return base::string16();
425 base::string16
DownloadItemModel::GetWarningConfirmButtonText() const {
426 // Should only be called if IsDangerous()
427 DCHECK(IsDangerous());
428 if (download_
->GetDangerType() ==
429 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
&&
430 download_crx_util::IsExtensionDownload(*download_
)) {
431 return l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD
);
433 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD
);
437 int64
DownloadItemModel::GetCompletedBytes() const {
438 return download_
->GetReceivedBytes();
441 int64
DownloadItemModel::GetTotalBytes() const {
442 return download_
->AllDataSaved() ? download_
->GetReceivedBytes() :
443 download_
->GetTotalBytes();
446 // TODO(asanka,rdsmith): Once 'open' moves exclusively to the
447 // ChromeDownloadManagerDelegate, we should calculate the percentage here
448 // instead of calling into the DownloadItem.
449 int DownloadItemModel::PercentComplete() const {
450 return download_
->PercentComplete();
453 bool DownloadItemModel::IsDangerous() const {
454 return download_
->IsDangerous();
457 bool DownloadItemModel::MightBeMalicious() const {
460 switch (download_
->GetDangerType()) {
461 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
462 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
463 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
464 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
465 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
:
468 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
469 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
470 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
471 case content::DOWNLOAD_DANGER_TYPE_MAX
:
472 // We shouldn't get any of these due to the IsDangerous() test above.
475 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
482 // If you change this definition of malicious, also update
483 // DownloadManagerImpl::NonMaliciousInProgressCount.
484 bool DownloadItemModel::IsMalicious() const {
485 if (!MightBeMalicious())
487 switch (download_
->GetDangerType()) {
488 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
489 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
490 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
491 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
:
494 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
495 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
496 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
497 case content::DOWNLOAD_DANGER_TYPE_MAX
:
498 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
499 // We shouldn't get any of these due to the MightBeMalicious() test above.
502 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
509 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
510 #if defined(FULL_SAFE_BROWSING)
513 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
520 bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const {
521 switch (download_
->GetState()) {
522 case DownloadItem::IN_PROGRESS
:
523 // If the download is dangerous or malicious, we should display a warning
524 // on the shelf until the user accepts the download.
528 // If the download is an extension, temporary, or will be opened
529 // automatically, then it should be removed from the shelf on completion.
530 // TODO(asanka): The logic for deciding opening behavior should be in a
531 // central location. http://crbug.com/167702
532 return (download_crx_util::IsExtensionDownload(*download_
) ||
533 download_
->IsTemporary() ||
534 download_
->GetOpenWhenComplete() ||
535 download_
->ShouldOpenFileBasedOnExtension());
537 case DownloadItem::COMPLETE
:
538 // If the download completed, then rely on GetAutoOpened() to check for
539 // opening behavior. This should accurately reflect whether the download
540 // was successfully opened. Extensions, for example, may fail to open.
541 return download_
->GetAutoOpened() || download_
->IsTemporary();
543 case DownloadItem::CANCELLED
:
544 case DownloadItem::INTERRUPTED
:
545 // Interrupted or cancelled downloads should remain on the shelf.
548 case DownloadItem::MAX_DOWNLOAD_STATE
:
556 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
557 return !download_
->IsSavePackageDownload() &&
558 !download_crx_util::IsExtensionDownload(*download_
);
561 bool DownloadItemModel::ShouldShowInShelf() const {
562 const DownloadItemModelData
* data
= DownloadItemModelData::Get(download_
);
563 return !data
|| data
->should_show_in_shelf();
566 void DownloadItemModel::SetShouldShowInShelf(bool should_show
) {
567 DownloadItemModelData
* data
= DownloadItemModelData::GetOrCreate(download_
);
568 data
->set_should_show_in_shelf(should_show
);
571 bool DownloadItemModel::ShouldNotifyUI() const {
573 Profile::FromBrowserContext(download_
->GetBrowserContext());
574 DownloadService
* download_service
=
575 DownloadServiceFactory::GetForBrowserContext(profile
);
576 DownloadHistory
* download_history
=
577 (download_service
? download_service
->GetDownloadHistory() : NULL
);
579 // The browser is only interested in new downloads. Ones that were restored
580 // from history are not displayed on the shelf. The downloads page
581 // independently listens for new downloads when it is active. Note that the UI
582 // will be notified of downloads even if they are not meant to be displayed on
583 // the shelf (i.e. ShouldShowInShelf() returns false). This is because:
584 // * The shelf isn't the only UI. E.g. on Android, the UI is the system
586 // * There are other UI activities that need to be performed. E.g. if the
587 // download was initiated from a new tab, then that tab should be closed.
589 // TODO(asanka): If an interrupted download is restored from history and is
590 // resumed, then ideally the UI should be notified.
591 return !download_history
||
592 !download_history
->WasRestoredFromHistory(download_
);
595 bool DownloadItemModel::WasUINotified() const {
596 const DownloadItemModelData
* data
= DownloadItemModelData::Get(download_
);
597 return data
&& data
->was_ui_notified();
600 void DownloadItemModel::SetWasUINotified(bool was_ui_notified
) {
601 DownloadItemModelData
* data
= DownloadItemModelData::GetOrCreate(download_
);
602 data
->set_was_ui_notified(was_ui_notified
);
605 bool DownloadItemModel::ShouldPreferOpeningInBrowser() const {
606 const DownloadItemModelData
* data
= DownloadItemModelData::Get(download_
);
607 return data
&& data
->should_prefer_opening_in_browser();
610 void DownloadItemModel::SetShouldPreferOpeningInBrowser(bool preference
) {
611 DownloadItemModelData
* data
= DownloadItemModelData::GetOrCreate(download_
);
612 data
->set_should_prefer_opening_in_browser(preference
);
615 base::string16
DownloadItemModel::GetProgressSizesString() const {
616 base::string16 size_ratio
;
617 int64 size
= GetCompletedBytes();
618 int64 total
= GetTotalBytes();
620 ui::DataUnits amount_units
= ui::GetByteDisplayUnits(total
);
621 base::string16 simple_size
= ui::FormatBytesWithUnits(size
, amount_units
, false);
623 // In RTL locales, we render the text "size/total" in an RTL context. This
624 // is problematic since a string such as "123/456 MB" is displayed
625 // as "MB 123/456" because it ends with an LTR run. In order to solve this,
626 // we mark the total string as an LTR string if the UI layout is
627 // right-to-left so that the string "456 MB" is treated as an LTR run.
628 base::string16 simple_total
= base::i18n::GetDisplayStringInLTRDirectionality(
629 ui::FormatBytesWithUnits(total
, amount_units
, true));
630 size_ratio
= l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES
,
631 simple_size
, simple_total
);
633 size_ratio
= ui::FormatBytes(size
);
638 base::string16
DownloadItemModel::GetInProgressStatusString() const {
639 DCHECK_EQ(DownloadItem::IN_PROGRESS
, download_
->GetState());
641 TimeDelta time_remaining
;
642 // time_remaining is only known if the download isn't paused.
643 bool time_remaining_known
= (!download_
->IsPaused() &&
644 download_
->TimeRemaining(&time_remaining
));
646 // Indication of progress. (E.g.:"100/200 MB" or "100MB")
647 base::string16 size_ratio
= GetProgressSizesString();
649 // The download is a CRX (app, extension, theme, ...) and it is being unpacked
651 if (download_
->AllDataSaved() &&
652 download_crx_util::IsExtensionDownload(*download_
)) {
653 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING
);
656 // A paused download: "100/120 MB, Paused"
657 if (download_
->IsPaused()) {
658 return l10n_util::GetStringFUTF16(
659 IDS_DOWNLOAD_STATUS_IN_PROGRESS
, size_ratio
,
660 l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED
));
663 // A download scheduled to be opened when complete: "Opening in 10 secs"
664 if (download_
->GetOpenWhenComplete()) {
665 if (!time_remaining_known
)
666 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE
);
668 return l10n_util::GetStringFUTF16(
669 IDS_DOWNLOAD_STATUS_OPEN_IN
,
670 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION
,
671 ui::TimeFormat::LENGTH_SHORT
, time_remaining
));
674 // In progress download with known time left: "100/120 MB, 10 secs left"
675 if (time_remaining_known
) {
676 return l10n_util::GetStringFUTF16(
677 IDS_DOWNLOAD_STATUS_IN_PROGRESS
, size_ratio
,
678 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING
,
679 ui::TimeFormat::LENGTH_SHORT
, time_remaining
));
682 // In progress download with no known time left and non-zero completed bytes:
683 // "100/120 MB" or "100 MB"
684 if (GetCompletedBytes() > 0)
687 // Instead of displaying "0 B" we say "Starting..."
688 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING
);
691 void DownloadItemModel::OpenUsingPlatformHandler() {
692 DownloadService
* download_service
=
693 DownloadServiceFactory::GetForBrowserContext(
694 download_
->GetBrowserContext());
695 if (!download_service
)
698 ChromeDownloadManagerDelegate
* delegate
=
699 download_service
->GetDownloadManagerDelegate();
702 delegate
->OpenDownloadUsingPlatformHandler(download_
);
703 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM
);