| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/download/download_ui_model.h" |
| |
| #include "base/i18n/rtl.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/download/offline_item_utils.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "net/base/mime_util.h" |
| #include "third_party/blink/public/common/mime_util/mime_util.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/l10n/time_format.h" |
| #include "ui/base/text/bytes_formatting.h" |
| #include "ui/gfx/text_elider.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "chrome/browser/chromeos/note_taking_helper.h" |
| #endif // defined(OS_CHROMEOS) |
| |
| using base::TimeDelta; |
| using download::DownloadItem; |
| using safe_browsing::DownloadFileType; |
| using offline_items_collection::FailState; |
| |
| namespace { |
| |
| // TODO(qinmin): Migrate this description generator to OfflineItemUtils once |
| // that component gets used to build desktop UI. |
| base::string16 FailStateMessage(FailState fail_state) { |
| int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; |
| base::string16 status_text; |
| |
| switch (fail_state) { |
| case FailState::FILE_ACCESS_DENIED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED; |
| break; |
| case FailState::FILE_NO_SPACE: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL; |
| break; |
| case FailState::FILE_NAME_TOO_LONG: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG; |
| break; |
| case FailState::FILE_TOO_LARGE: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE; |
| break; |
| case FailState::FILE_VIRUS_INFECTED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS; |
| break; |
| case FailState::FILE_TRANSIENT_ERROR: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM; |
| break; |
| case FailState::FILE_BLOCKED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED; |
| break; |
| case FailState::FILE_SECURITY_CHECK_FAILED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED; |
| break; |
| case FailState::FILE_TOO_SHORT: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT; |
| break; |
| case FailState::FILE_SAME_AS_SOURCE: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_SAME_AS_SOURCE; |
| break; |
| case FailState::NETWORK_INVALID_REQUEST: |
| case FailState::NETWORK_FAILED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR; |
| break; |
| case FailState::NETWORK_TIMEOUT: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT; |
| break; |
| case FailState::NETWORK_DISCONNECTED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED; |
| break; |
| case FailState::NETWORK_SERVER_DOWN: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN; |
| break; |
| case FailState::SERVER_FAILED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM; |
| break; |
| case FailState::SERVER_BAD_CONTENT: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE; |
| break; |
| case FailState::USER_CANCELED: |
| string_id = IDS_DOWNLOAD_STATUS_CANCELLED; |
| break; |
| case FailState::USER_SHUTDOWN: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN; |
| break; |
| case FailState::CRASH: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH; |
| break; |
| case FailState::SERVER_UNAUTHORIZED: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED; |
| break; |
| case FailState::SERVER_CERT_PROBLEM: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM; |
| break; |
| case FailState::SERVER_FORBIDDEN: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FORBIDDEN; |
| break; |
| case FailState::SERVER_UNREACHABLE: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNREACHABLE; |
| break; |
| case FailState::SERVER_CONTENT_LENGTH_MISMATCH: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CONTENT_LENGTH_MISMATCH; |
| break; |
| case FailState::NO_FAILURE: |
| NOTREACHED(); |
| FALLTHROUGH; |
| // fallthrough |
| case FailState::CANNOT_DOWNLOAD: |
| case FailState::NETWORK_INSTABILITY: |
| case FailState::SERVER_NO_RANGE: |
| case FailState::SERVER_CROSS_ORIGIN_REDIRECT: |
| case FailState::FILE_FAILED: |
| case FailState::FILE_HASH_MISMATCH: |
| string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; |
| } |
| |
| status_text = l10n_util::GetStringUTF16(string_id); |
| |
| return status_text; |
| } |
| |
| } // namespace |
| |
| DownloadUIModel::DownloadUIModel() = default; |
| |
| DownloadUIModel::~DownloadUIModel() = default; |
| |
| void DownloadUIModel::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void DownloadUIModel::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool DownloadUIModel::HasSupportedImageMimeType() const { |
| if (blink::IsSupportedImageMimeType(GetMimeType())) |
| return true; |
| |
| std::string mime; |
| base::FilePath::StringType extension_with_dot = |
| GetTargetFilePath().FinalExtension(); |
| if (!extension_with_dot.empty() && |
| net::GetWellKnownMimeTypeFromExtension(extension_with_dot.substr(1), |
| &mime) && |
| blink::IsSupportedImageMimeType(mime)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| base::string16 DownloadUIModel::GetProgressSizesString() const { |
| base::string16 size_ratio; |
| int64_t size = GetCompletedBytes(); |
| int64_t total = GetTotalBytes(); |
| if (total > 0) { |
| ui::DataUnits amount_units = ui::GetByteDisplayUnits(total); |
| base::string16 simple_size = |
| ui::FormatBytesWithUnits(size, amount_units, false); |
| |
| // In RTL locales, we render the text "size/total" in an RTL context. This |
| // is problematic since a string such as "123/456 MB" is displayed |
| // as "MB 123/456" because it ends with an LTR run. In order to solve this, |
| // we mark the total string as an LTR string if the UI layout is |
| // right-to-left so that the string "456 MB" is treated as an LTR run. |
| base::string16 simple_total = |
| base::i18n::GetDisplayStringInLTRDirectionality( |
| ui::FormatBytesWithUnits(total, amount_units, true)); |
| size_ratio = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES, |
| simple_size, simple_total); |
| } else { |
| size_ratio = ui::FormatBytes(size); |
| } |
| return size_ratio; |
| } |
| |
| base::string16 DownloadUIModel::GetInterruptReasonText() const { |
| if (GetState() != DownloadItem::INTERRUPTED || |
| GetLastFailState() == FailState::USER_CANCELED) { |
| return base::string16(); |
| } |
| return FailStateMessage(GetLastFailState()); |
| } |
| |
| base::string16 DownloadUIModel::GetStatusText() const { |
| base::string16 status_text; |
| switch (GetState()) { |
| case DownloadItem::IN_PROGRESS: |
| status_text = GetInProgressStatusString(); |
| break; |
| case DownloadItem::COMPLETE: |
| if (GetFileExternallyRemoved()) { |
| status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED); |
| } else { |
| status_text.clear(); |
| } |
| break; |
| case DownloadItem::CANCELLED: |
| status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED); |
| break; |
| case DownloadItem::INTERRUPTED: { |
| FailState fail_state = GetLastFailState(); |
| if (fail_state != FailState::USER_CANCELED) { |
| base::string16 message = |
| OfflineItemUtils::GetFailStateMessage(fail_state); |
| status_text = l10n_util::GetStringFUTF16( |
| IDS_DOWNLOAD_STATUS_INTERRUPTED, message); |
| } else { |
| // Same as DownloadItem::CANCELLED. |
| status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED); |
| } |
| break; |
| } |
| default: |
| NOTREACHED(); |
| } |
| |
| return status_text; |
| } |
| |
| base::string16 DownloadUIModel::GetTooltipText(const gfx::FontList& font_list, |
| int max_width) const { |
| base::string16 tooltip = gfx::ElideFilename( |
| GetFileNameToReportUser(), font_list, max_width, gfx::Typesetter::NATIVE); |
| if (GetState() == DownloadItem::INTERRUPTED && |
| GetLastFailState() != FailState::USER_CANCELED) { |
| tooltip += base::ASCIIToUTF16("\n"); |
| tooltip += gfx::ElideText( |
| OfflineItemUtils::GetFailStateMessage(GetLastFailState()), font_list, |
| max_width, gfx::ELIDE_TAIL, gfx::Typesetter::NATIVE); |
| } |
| return tooltip; |
| } |
| |
| base::string16 DownloadUIModel::GetWarningText(const gfx::FontList& font_list, |
| int base_width) const { |
| // Should only be called if IsDangerous(). |
| DCHECK(IsDangerous()); |
| base::string16 elided_filename = |
| gfx::ElideFilename(GetFileNameToReportUser(), font_list, base_width, |
| gfx::Typesetter::BROWSER); |
| switch (GetDangerType()) { |
| case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: { |
| return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); |
| } |
| case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: { |
| if (IsExtensionDownload()) { |
| return l10n_util::GetStringUTF16( |
| IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION); |
| } else { |
| return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, |
| elided_filename); |
| } |
| } |
| case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: |
| case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { |
| return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, |
| elided_filename); |
| } |
| case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { |
| return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, |
| elided_filename); |
| } |
| case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { |
| return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, |
| elided_filename); |
| } |
| case download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: |
| case download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: |
| case download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: |
| case download::DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY: |
| case download::DOWNLOAD_DANGER_TYPE_MAX: { |
| break; |
| } |
| } |
| NOTREACHED(); |
| return base::string16(); |
| } |
| |
| base::string16 DownloadUIModel::GetWarningConfirmButtonText() const { |
| // Should only be called if IsDangerous() |
| DCHECK(IsDangerous()); |
| if (GetDangerType() == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE && |
| IsExtensionDownload()) { |
| return l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD); |
| } else { |
| return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD); |
| } |
| } |
| |
| ContentId DownloadUIModel::GetContentId() const { |
| NOTREACHED(); |
| return ContentId(); |
| } |
| |
| Profile* DownloadUIModel::profile() const { |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| base::string16 DownloadUIModel::GetTabProgressStatusText() const { |
| return base::string16(); |
| } |
| |
| int64_t DownloadUIModel::GetCompletedBytes() const { |
| return 0; |
| } |
| |
| int64_t DownloadUIModel::GetTotalBytes() const { |
| return 0; |
| } |
| |
| int DownloadUIModel::PercentComplete() const { |
| return -1; |
| } |
| |
| bool DownloadUIModel::IsDangerous() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::MightBeMalicious() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::IsMalicious() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::ShouldAllowDownloadFeedback() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::ShouldRemoveFromShelfWhenComplete() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::ShouldShowDownloadStartedAnimation() const { |
| return true; |
| } |
| |
| bool DownloadUIModel::ShouldShowInShelf() const { |
| return true; |
| } |
| |
| void DownloadUIModel::SetShouldShowInShelf(bool should_show) {} |
| |
| bool DownloadUIModel::ShouldNotifyUI() const { |
| return true; |
| } |
| |
| bool DownloadUIModel::WasUINotified() const { |
| return false; |
| } |
| |
| void DownloadUIModel::SetWasUINotified(bool should_notify) {} |
| |
| bool DownloadUIModel::ShouldPreferOpeningInBrowser() const { |
| return true; |
| } |
| |
| void DownloadUIModel::SetShouldPreferOpeningInBrowser(bool preference) {} |
| |
| DownloadFileType::DangerLevel DownloadUIModel::GetDangerLevel() const { |
| return DownloadFileType::NOT_DANGEROUS; |
| } |
| |
| void DownloadUIModel::SetDangerLevel( |
| DownloadFileType::DangerLevel danger_level) {} |
| |
| void DownloadUIModel::OpenUsingPlatformHandler() {} |
| |
| bool DownloadUIModel::IsBeingRevived() const { |
| return true; |
| } |
| |
| void DownloadUIModel::SetIsBeingRevived(bool is_being_revived) {} |
| |
| DownloadItem* DownloadUIModel::download() { |
| return nullptr; |
| } |
| |
| base::FilePath DownloadUIModel::GetFileNameToReportUser() const { |
| return base::FilePath(); |
| } |
| |
| base::FilePath DownloadUIModel::GetTargetFilePath() const { |
| return base::FilePath(); |
| } |
| |
| void DownloadUIModel::OpenDownload() {} |
| |
| download::DownloadItem::DownloadState DownloadUIModel::GetState() const { |
| return download::DownloadItem::IN_PROGRESS; |
| } |
| |
| bool DownloadUIModel::IsPaused() const { |
| return false; |
| } |
| |
| download::DownloadDangerType DownloadUIModel::GetDangerType() const { |
| return download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS; |
| } |
| |
| bool DownloadUIModel::GetOpenWhenComplete() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::TimeRemaining(base::TimeDelta* remaining) const { |
| return false; |
| } |
| |
| bool DownloadUIModel::GetOpened() const { |
| return false; |
| } |
| |
| void DownloadUIModel::SetOpened(bool opened) {} |
| |
| bool DownloadUIModel::IsDone() const { |
| return false; |
| } |
| |
| void DownloadUIModel::Pause() {} |
| |
| void DownloadUIModel::Resume() {} |
| |
| void DownloadUIModel::Cancel(bool user_cancel) {} |
| |
| void DownloadUIModel::Remove() {} |
| |
| void DownloadUIModel::SetOpenWhenComplete(bool open) {} |
| |
| FailState DownloadUIModel::GetLastFailState() const { |
| return FailState::NO_FAILURE; |
| } |
| |
| base::FilePath DownloadUIModel::GetFullPath() const { |
| return base::FilePath(); |
| } |
| |
| bool DownloadUIModel::CanResume() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::AllDataSaved() const { |
| return false; |
| } |
| |
| bool DownloadUIModel::GetFileExternallyRemoved() const { |
| return false; |
| } |
| |
| GURL DownloadUIModel::GetURL() const { |
| return GURL(); |
| } |
| |
| GURL DownloadUIModel::GetOriginalURL() const { |
| return GURL(); |
| } |
| |
| bool DownloadUIModel::ShouldPromoteOrigin() const { |
| return false; |
| } |
| |
| #if !defined(OS_ANDROID) |
| bool DownloadUIModel::IsCommandEnabled( |
| const DownloadCommands* download_commands, |
| DownloadCommands::Command command) const { |
| switch (command) { |
| case DownloadCommands::SHOW_IN_FOLDER: |
| case DownloadCommands::OPEN_WHEN_COMPLETE: |
| case DownloadCommands::PLATFORM_OPEN: |
| case DownloadCommands::ALWAYS_OPEN_TYPE: |
| NOTREACHED(); |
| return false; |
| case DownloadCommands::CANCEL: |
| return !IsDone(); |
| case DownloadCommands::PAUSE: |
| return !IsDone() && !IsPaused() && |
| GetState() == download::DownloadItem::IN_PROGRESS; |
| case DownloadCommands::RESUME: |
| return CanResume() && |
| (IsPaused() || GetState() != download::DownloadItem::IN_PROGRESS); |
| case DownloadCommands::COPY_TO_CLIPBOARD: |
| return download_commands->CanBeCopiedToClipboard(); |
| case DownloadCommands::ANNOTATE: |
| return GetState() == download::DownloadItem::COMPLETE; |
| case DownloadCommands::DISCARD: |
| case DownloadCommands::KEEP: |
| case DownloadCommands::LEARN_MORE_SCANNING: |
| case DownloadCommands::LEARN_MORE_INTERRUPTED: |
| return true; |
| } |
| NOTREACHED(); |
| return false; |
| } |
| |
| bool DownloadUIModel::IsCommandChecked( |
| const DownloadCommands* download_commands, |
| DownloadCommands::Command command) const { |
| switch (command) { |
| case DownloadCommands::OPEN_WHEN_COMPLETE: |
| case DownloadCommands::ALWAYS_OPEN_TYPE: |
| NOTREACHED(); |
| return false; |
| case DownloadCommands::PAUSE: |
| case DownloadCommands::RESUME: |
| return IsPaused(); |
| case DownloadCommands::SHOW_IN_FOLDER: |
| case DownloadCommands::PLATFORM_OPEN: |
| case DownloadCommands::CANCEL: |
| case DownloadCommands::DISCARD: |
| case DownloadCommands::KEEP: |
| case DownloadCommands::LEARN_MORE_SCANNING: |
| case DownloadCommands::LEARN_MORE_INTERRUPTED: |
| case DownloadCommands::COPY_TO_CLIPBOARD: |
| case DownloadCommands::ANNOTATE: |
| return false; |
| } |
| return false; |
| } |
| |
| void DownloadUIModel::ExecuteCommand(DownloadCommands* download_commands, |
| DownloadCommands::Command command) { |
| switch (command) { |
| case DownloadCommands::SHOW_IN_FOLDER: |
| case DownloadCommands::OPEN_WHEN_COMPLETE: |
| case DownloadCommands::ALWAYS_OPEN_TYPE: |
| NOTREACHED(); |
| break; |
| case DownloadCommands::PLATFORM_OPEN: |
| OpenUsingPlatformHandler(); |
| break; |
| case DownloadCommands::CANCEL: |
| Cancel(true /* Cancelled by user */); |
| break; |
| case DownloadCommands::DISCARD: |
| Remove(); |
| break; |
| case DownloadCommands::KEEP: |
| case DownloadCommands::LEARN_MORE_SCANNING: |
| NOTREACHED(); |
| break; |
| case DownloadCommands::LEARN_MORE_INTERRUPTED: |
| download_commands->GetBrowser()->OpenURL(content::OpenURLParams( |
| download_commands->GetLearnMoreURLForInterruptedDownload(), |
| content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_LINK, false)); |
| break; |
| case DownloadCommands::PAUSE: |
| Pause(); |
| break; |
| case DownloadCommands::RESUME: |
| Resume(); |
| break; |
| case DownloadCommands::COPY_TO_CLIPBOARD: |
| download_commands->CopyFileAsImageToClipboard(); |
| break; |
| case DownloadCommands::ANNOTATE: |
| #if defined(OS_CHROMEOS) |
| if (HasSupportedImageMimeType()) { |
| chromeos::NoteTakingHelper::Get()->LaunchAppForNewNote( |
| profile(), GetTargetFilePath()); |
| } |
| #endif // defined(OS_CHROMEOS) |
| break; |
| } |
| } |
| #endif |
| |
| std::string DownloadUIModel::GetMimeType() const { |
| return "text/html"; |
| } |
| |
| bool DownloadUIModel::IsExtensionDownload() const { |
| return false; |
| } |
| |
| base::string16 DownloadUIModel::GetInProgressStatusString() const { |
| DCHECK_EQ(DownloadItem::IN_PROGRESS, GetState()); |
| |
| TimeDelta time_remaining; |
| // time_remaining is only known if the download isn't paused. |
| bool time_remaining_known = (!IsPaused() && TimeRemaining(&time_remaining)); |
| |
| // Indication of progress. (E.g.:"100/200 MB" or "100MB") |
| base::string16 size_ratio = GetProgressSizesString(); |
| |
| // The download is a CRX (app, extension, theme, ...) and it is being unpacked |
| // and validated. |
| if (AllDataSaved() && IsExtensionDownload()) { |
| return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING); |
| } |
| |
| // A paused download: "100/120 MB, Paused" |
| if (IsPaused()) { |
| return l10n_util::GetStringFUTF16( |
| IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio, |
| l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED)); |
| } |
| |
| // A download scheduled to be opened when complete: "Opening in 10 secs" |
| if (GetOpenWhenComplete()) { |
| if (!time_remaining_known) |
| return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE); |
| |
| return l10n_util::GetStringFUTF16( |
| IDS_DOWNLOAD_STATUS_OPEN_IN, |
| ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, |
| ui::TimeFormat::LENGTH_SHORT, time_remaining)); |
| } |
| |
| // In progress download with known time left: "100/120 MB, 10 secs left" |
| if (time_remaining_known) { |
| return l10n_util::GetStringFUTF16( |
| IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio, |
| ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING, |
| ui::TimeFormat::LENGTH_SHORT, time_remaining)); |
| } |
| |
| // In progress download with no known time left and non-zero completed bytes: |
| // "100/120 MB" or "100 MB" |
| if (GetCompletedBytes() > 0) |
| return size_ratio; |
| |
| // Instead of displaying "0 B" we say "Starting..." |
| return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING); |
| } |