Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / chrome / browser / download / download_item_model.cc
blob47793eb95611458793c0eb97cf47463530c3febb
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 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;
68 private:
69 DownloadItemModelData();
70 virtual ~DownloadItemModelData() {}
72 static const char kKey[];
74 // Whether the download should be displayed in the download shelf. True by
75 // default.
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
82 // for the file type.
83 bool should_prefer_opening_in_browser_;
86 // static
87 const char DownloadItemModelData::kKey[] = "DownloadItemModelData key";
89 // static
90 const DownloadItemModelData* DownloadItemModelData::Get(
91 const DownloadItem* download) {
92 return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey));
95 // static
96 DownloadItemModelData* DownloadItemModelData::GetOrCreate(
97 DownloadItem* download) {
98 DownloadItemModelData* data =
99 static_cast<DownloadItemModelData*>(download->GetUserData(kKey));
100 if (data == NULL) {
101 data = new DownloadItemModelData();
102 download->SetUserData(kKey, data);
104 return 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;
119 break;
120 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
121 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL;
122 break;
123 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
124 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG;
125 break;
126 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
127 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE;
128 break;
129 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
130 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS;
131 break;
132 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
133 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM;
134 break;
135 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
136 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED;
137 break;
138 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
139 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED;
140 break;
141 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
142 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT;
143 break;
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;
147 break;
148 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
149 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT;
150 break;
151 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
152 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED;
153 break;
154 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
155 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN;
156 break;
157 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
158 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM;
159 break;
160 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
161 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE;
162 break;
163 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
164 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
165 break;
166 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
167 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN;
168 break;
169 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
170 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH;
171 break;
172 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
173 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED;
174 break;
175 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
176 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM;
177 break;
178 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
179 NOTREACHED();
180 // fallthrough
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;
197 break;
198 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
199 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL;
200 break;
201 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
202 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG;
203 break;
204 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
205 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE;
206 break;
207 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
208 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS;
209 break;
210 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
211 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM;
212 break;
213 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
214 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED;
215 break;
216 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
217 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED;
218 break;
219 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
220 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT;
221 break;
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;
225 break;
226 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
227 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT;
228 break;
229 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
230 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED;
231 break;
232 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
233 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN;
234 break;
235 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
236 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM;
237 break;
238 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
239 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE;
240 break;
241 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
242 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
243 break;
244 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
245 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN;
246 break;
247 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
248 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH;
249 break;
250 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
251 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED;
252 break;
253 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
254 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM;
255 break;
256 case content::DOWNLOAD_INTERRUPT_REASON_NONE:
257 NOTREACHED();
258 // fallthrough
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);
267 return status_text;
270 } // namespace
272 // -----------------------------------------------------------------------------
273 // DownloadItemModel
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();
294 break;
295 case DownloadItem::COMPLETE:
296 if (download_->GetFileExternallyRemoved()) {
297 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED);
298 } else {
299 status_text.clear();
301 break;
302 case DownloadItem::CANCELLED:
303 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
304 break;
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);
311 } else {
312 // Same as DownloadItem::CANCELLED.
313 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
315 break;
317 default:
318 NOTREACHED();
321 return status_text;
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);
334 if (total) {
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);
341 } else {
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,
355 remaining);
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);
378 return tooltip;
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,
387 base_width);
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);
396 } else {
397 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
398 elided_filename);
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,
404 elided_filename);
406 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
407 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
408 elided_filename);
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: {
418 break;
421 NOTREACHED();
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);
432 } else {
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 {
458 if (!IsDangerous())
459 return false;
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:
466 return true;
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.
473 NOTREACHED();
474 // Fallthrough.
475 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
476 return false;
478 NOTREACHED();
479 return false;
482 // If you change this definition of malicious, also update
483 // DownloadManagerImpl::NonMaliciousInProgressCount.
484 bool DownloadItemModel::IsMalicious() const {
485 if (!MightBeMalicious())
486 return false;
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:
492 return true;
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.
500 NOTREACHED();
501 // Fallthrough.
502 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
503 return false;
505 NOTREACHED();
506 return false;
509 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
510 #if defined(FULL_SAFE_BROWSING)
511 if (!IsDangerous())
512 return false;
513 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
514 *download_);
515 #else
516 return false;
517 #endif
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.
525 if (IsDangerous())
526 return false;
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.
546 return false;
548 case DownloadItem::MAX_DOWNLOAD_STATE:
549 NOTREACHED();
552 NOTREACHED();
553 return false;
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 {
572 Profile* profile =
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
585 // DownloadManager.
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();
619 if (total > 0) {
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);
632 } else {
633 size_ratio = ui::FormatBytes(size);
635 return size_ratio;
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
650 // and validated.
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)
685 return size_ratio;
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)
696 return;
698 ChromeDownloadManagerDelegate* delegate =
699 download_service->GetDownloadManagerDelegate();
700 if (!delegate)
701 return;
702 delegate->OpenDownloadUsingPlatformHandler(download_);
703 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM);