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_;
67 DownloadItemModelData();
68 ~DownloadItemModelData() override {}
70 static const char kKey[];
74 const char DownloadItemModelData::kKey[] = "DownloadItemModelData key";
77 const DownloadItemModelData* DownloadItemModelData::Get(
78 const DownloadItem* download) {
79 return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey));
83 DownloadItemModelData* DownloadItemModelData::GetOrCreate(
84 DownloadItem* download) {
85 DownloadItemModelData* data =
86 static_cast<DownloadItemModelData*>(download->GetUserData(kKey));
88 data = new DownloadItemModelData();
89 download->SetUserData(kKey, data);
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) {
101 base::string16 InterruptReasonStatusMessage(int reason) {
102 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
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;
108 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
109 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL;
111 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
112 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG;
114 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
115 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE;
117 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
118 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS;
120 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
121 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM;
123 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
124 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED;
126 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
127 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED;
129 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
130 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT;
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;
136 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
137 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT;
139 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
140 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED;
142 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
143 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN;
145 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
146 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM;
148 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
149 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE;
151 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
152 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
154 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
155 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN;
157 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
158 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH;
160 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
161 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED;
163 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
164 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM;
166 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
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;
175 return l10n_util::GetStringUTF16(string_id);
178 base::string16 InterruptReasonMessage(int reason) {
179 int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
180 base::string16 status_text;
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;
186 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
187 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL;
189 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
190 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG;
192 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
193 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE;
195 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
196 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS;
198 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
199 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM;
201 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
202 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED;
204 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
205 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED;
207 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
208 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT;
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;
214 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
215 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT;
217 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
218 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED;
220 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
221 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN;
223 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
224 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM;
226 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
227 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE;
229 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
230 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
232 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
233 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN;
235 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
236 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH;
238 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
239 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED;
241 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
242 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM;
244 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
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;
253 status_text = l10n_util::GetStringUTF16(string_id);
260 // -----------------------------------------------------------------------------
263 DownloadItemModel::DownloadItemModel(DownloadItem* download)
264 : download_(download) {}
266 DownloadItemModel::~DownloadItemModel() {}
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();
274 return InterruptReasonMessage(download_->GetLastReason());
277 base::string16 DownloadItemModel::GetStatusText() const {
278 base::string16 status_text;
279 switch (download_->GetState()) {
280 case DownloadItem::IN_PROGRESS:
281 status_text = GetInProgressStatusString();
283 case DownloadItem::COMPLETE:
284 if (download_->GetFileExternallyRemoved()) {
285 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED);
290 case DownloadItem::CANCELLED:
291 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
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);
300 // Same as DownloadItem::CANCELLED.
301 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
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;
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);
323 base::string16 total_text = ui::FormatBytes(total);
324 base::i18n::AdjustStringForLocaleDirection(&total_text);
326 base::i18n::AdjustStringForLocaleDirection(&received_size);
327 amount = l10n_util::GetStringFUTF16(
328 IDS_DOWNLOAD_TAB_PROGRESS_SIZE, received_size, total_text);
330 amount.assign(received_size);
332 int64 current_speed = download_->CurrentSpeed();
333 base::string16 speed_text = ui::FormatSpeed(current_speed);
334 base::i18n::AdjustStringForLocaleDirection(&speed_text);
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,
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);
351 return l10n_util::GetStringFUTF16(
352 IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text, amount, time_remaining);
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);
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,
376 switch (download_->GetDangerType()) {
377 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
378 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
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);
385 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
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,
394 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
395 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
398 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
399 return l10n_util::GetStringFUTF16(
400 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename);
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: {
410 return base::string16();
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);
421 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
425 int64 DownloadItemModel::GetCompletedBytes() const {
426 return download_->GetReceivedBytes();
429 int64 DownloadItemModel::GetTotalBytes() const {
430 return download_->AllDataSaved() ? download_->GetReceivedBytes() :
431 download_->GetTotalBytes();
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();
441 bool DownloadItemModel::IsDangerous() const {
442 return download_->IsDangerous();
445 bool DownloadItemModel::MightBeMalicious() const {
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:
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.
463 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
470 // If you change this definition of malicious, also update
471 // DownloadManagerImpl::NonMaliciousInProgressCount.
472 bool DownloadItemModel::IsMalicious() const {
473 if (!MightBeMalicious())
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:
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.
490 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
497 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
498 #if defined(FULL_SAFE_BROWSING)
501 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
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.
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());
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();
531 case DownloadItem::CANCELLED:
532 case DownloadItem::INTERRUPTED:
533 // Interrupted or cancelled downloads should remain on the shelf.
536 case DownloadItem::MAX_DOWNLOAD_STATE:
544 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
545 return !download_->IsSavePackageDownload() &&
546 !download_crx_util::IsExtensionDownload(*download_);
549 bool DownloadItemModel::ShouldShowInShelf() const {
550 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
551 return !data || data->should_show_in_shelf_;
554 void DownloadItemModel::SetShouldShowInShelf(bool should_show) {
555 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
556 data->should_show_in_shelf_ = should_show;
559 bool DownloadItemModel::ShouldNotifyUI() const {
561 Profile::FromBrowserContext(download_->GetBrowserContext());
562 DownloadService* download_service =
563 DownloadServiceFactory::GetForBrowserContext(profile);
564 DownloadHistory* download_history =
565 (download_service ? download_service->GetDownloadHistory() : NULL);
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
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.
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_);
583 bool DownloadItemModel::WasUINotified() const {
584 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
585 return data && data->was_ui_notified_;
588 void DownloadItemModel::SetWasUINotified(bool was_ui_notified) {
589 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
590 data->was_ui_notified_ = was_ui_notified;
593 bool DownloadItemModel::ShouldPreferOpeningInBrowser() const {
594 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
595 return data && data->should_prefer_opening_in_browser_;
598 void DownloadItemModel::SetShouldPreferOpeningInBrowser(bool preference) {
599 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
600 data->should_prefer_opening_in_browser_ = preference;
603 bool DownloadItemModel::IsDangerousFileBasedOnType() const {
604 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
605 return data && data->is_dangerous_file_based_on_type_;
608 void DownloadItemModel::SetIsDangerousFileBasedOnType(bool dangerous) {
609 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
610 data->is_dangerous_file_based_on_type_ = dangerous;
613 base::string16 DownloadItemModel::GetProgressSizesString() const {
614 base::string16 size_ratio;
615 int64 size = GetCompletedBytes();
616 int64 total = GetTotalBytes();
618 ui::DataUnits amount_units = ui::GetByteDisplayUnits(total);
619 base::string16 simple_size = ui::FormatBytesWithUnits(size, amount_units, false);
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);
631 size_ratio = ui::FormatBytes(size);
636 base::string16 DownloadItemModel::GetInProgressStatusString() const {
637 DCHECK_EQ(DownloadItem::IN_PROGRESS, download_->GetState());
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));
644 // Indication of progress. (E.g.:"100/200 MB" or "100MB")
645 base::string16 size_ratio = GetProgressSizesString();
647 // The download is a CRX (app, extension, theme, ...) and it is being unpacked
649 if (download_->AllDataSaved() &&
650 download_crx_util::IsExtensionDownload(*download_)) {
651 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING);
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));
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);
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));
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));
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)
685 // Instead of displaying "0 B" we say "Starting..."
686 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING);
689 void DownloadItemModel::OpenUsingPlatformHandler() {
690 DownloadService* download_service =
691 DownloadServiceFactory::GetForBrowserContext(
692 download_->GetBrowserContext());
693 if (!download_service)
696 ChromeDownloadManagerDelegate* delegate =
697 download_service->GetDownloadManagerDelegate();
700 delegate->OpenDownloadUsingPlatformHandler(download_);
701 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM);