blob: 82bace17ea6d57b8c31d20184fce51c636fba356 [file] [log] [blame]
// 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/feature_list.h"
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/download/download_commands.h"
#include "chrome/browser/download/offline_item_utils.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/safe_browsing/buildflags.h"
#include "components/safe_browsing/core/common/features.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"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/browser.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/note_taking_helper.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
using download::DownloadItem;
using offline_items_collection::FailState;
using safe_browsing::DownloadFileType;
namespace {
// TODO(qinmin): Migrate this description generator to OfflineItemUtils once
// that component gets used to build desktop UI.
std::u16string FailStateDescription(FailState fail_state) {
int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
std::u16string 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);
}
base::WeakPtr<DownloadUIModel> DownloadUIModel::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
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;
}
std::u16string DownloadUIModel::GetProgressSizesString() const {
std::u16string size_ratio;
int64_t size = GetCompletedBytes();
int64_t total = GetTotalBytes();
if (total > 0) {
ui::DataUnits amount_units = ui::GetByteDisplayUnits(total);
std::u16string 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.
std::u16string 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;
}
std::u16string DownloadUIModel::GetStatusText() const {
switch (GetState()) {
case DownloadItem::IN_PROGRESS:
return GetInProgressStatusText();
case DownloadItem::COMPLETE:
return GetCompletedStatusText();
case DownloadItem::INTERRUPTED: {
const FailState fail_state = GetLastFailState();
if (fail_state != FailState::USER_CANCELED) {
return GetInterruptedStatusText(fail_state);
}
}
FALLTHROUGH;
case DownloadItem::CANCELLED:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
case DownloadItem::MAX_DOWNLOAD_STATE:
NOTREACHED();
return std::u16string();
}
}
std::u16string DownloadUIModel::GetTooltipText() const {
std::u16string tooltip = GetFileNameToReportUser().LossyDisplayName();
if (GetState() == DownloadItem::INTERRUPTED &&
GetLastFailState() != FailState::USER_CANCELED) {
tooltip += u"\n" + GetFailStateMessage(GetLastFailState());
}
return tooltip;
}
// Ordering of the warning texts should be the same as order in the
// GetDesiredDownloadItemMode() method.
std::u16string DownloadUIModel::GetWarningText(const std::u16string& filename,
size_t* offset) const {
*offset = std::string::npos;
if (ShouldShowIncognitoWarning()) {
return l10n_util::GetStringFUTF16(IDS_PROMPT_INCOGNITO_WARNING, filename,
offset);
}
switch (GetMixedContentStatus()) {
case download::DownloadItem::MixedContentStatus::BLOCK:
return l10n_util::GetStringFUTF16(
IDS_PROMPT_DOWNLOAD_MIXED_CONTENT_BLOCKED, filename, offset);
case download::DownloadItem::MixedContentStatus::WARN:
return l10n_util::GetStringFUTF16(
IDS_PROMPT_DOWNLOAD_MIXED_CONTENT_WARNING, filename, offset);
case download::DownloadItem::MixedContentStatus::UNKNOWN:
case download::DownloadItem::MixedContentStatus::SAFE:
case download::DownloadItem::MixedContentStatus::VALIDATED:
case download::DownloadItem::MixedContentStatus::SILENT_BLOCK:
break;
}
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:
return IsExtensionDownload()
? l10n_util::GetStringUTF16(
IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION)
: l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
filename, offset);
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
filename, offset);
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE: {
return base::FeatureList::IsEnabled(
safe_browsing::kSafeBrowsingCTDownloadWarning)
? l10n_util::GetStringFUTF16(
IDS_PROMPT_DANGEROUS_DOWNLOAD_ACCOUNT_COMPROMISE,
filename, offset)
: l10n_util::GetStringFUTF16(
IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, filename, offset);
}
case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
bool request_ap_verdicts = false;
#if BUILDFLAG(FULL_SAFE_BROWSING)
request_ap_verdicts =
safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
profile())
->IsUnderAdvancedProtection();
#endif
return l10n_util::GetStringFUTF16(
request_ap_verdicts
? IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT_IN_ADVANCED_PROTECTION
: IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
filename, offset);
}
case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
filename, offset);
case download::DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE:
return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_BLOCKED_TOO_LARGE,
filename, offset);
case download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED:
return l10n_util::GetStringFUTF16(
IDS_PROMPT_DOWNLOAD_BLOCKED_PASSWORD_PROTECTED, filename, offset);
case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING:
return l10n_util::GetStringFUTF16(
IDS_PROMPT_DOWNLOAD_SENSITIVE_CONTENT_WARNING, filename, offset);
case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK:
return l10n_util::GetStringFUTF16(
IDS_PROMPT_DOWNLOAD_SENSITIVE_CONTENT_BLOCKED, filename, offset);
case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
return l10n_util::GetStringFUTF16(IDS_PROMPT_DEEP_SCANNING, filename,
offset);
case download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE:
case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE:
case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS:
case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
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_ALLOWLISTED_BY_POLICY:
case download::DOWNLOAD_DANGER_TYPE_MAX:
break;
}
return std::u16string();
}
std::u16string DownloadUIModel::GetWarningConfirmButtonText() const {
const auto kDangerousFile = download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
int warningConfirmButtonTextId = IDS_CONFIRM_DOWNLOAD;
if (ShouldShowIncognitoWarning()) {
warningConfirmButtonTextId = IDS_DOWNLOAD_ANYWAY;
} else if (GetDangerType() == kDangerousFile && IsExtensionDownload()) {
warningConfirmButtonTextId = IDS_CONTINUE_EXTENSION_DOWNLOAD;
}
return l10n_util::GetStringUTF16(warningConfirmButtonTextId);
}
std::u16string DownloadUIModel::GetShowInFolderText() const {
std::u16string where = GetWebDriveName();
if (where.empty()) {
// "Show in <folder/Finder>"
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_SHOW);
}
// "Show in <WEB_DRIVE>"
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_LINK_SHOW_IN_WEB_DRIVE, where);
}
ContentId DownloadUIModel::GetContentId() const {
NOTREACHED();
return ContentId();
}
Profile* DownloadUIModel::profile() const {
NOTREACHED();
return nullptr;
}
std::u16string DownloadUIModel::GetTabProgressStatusText() const {
return std::u16string();
}
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::IsMixedContent() const {
return false;
}
bool DownloadUIModel::ShouldShowIncognitoWarning() 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) {}
download::DownloadItem::MixedContentStatus
DownloadUIModel::GetMixedContentStatus() const {
return download::DownloadItem::MixedContentStatus::UNKNOWN;
}
void DownloadUIModel::OpenUsingPlatformHandler() {}
bool DownloadUIModel::IsBeingRevived() const {
return true;
}
void DownloadUIModel::SetIsBeingRevived(bool is_being_revived) {}
DownloadItem* DownloadUIModel::download() {
return nullptr;
}
std::u16string DownloadUIModel::GetWebDriveName() const {
return std::u16string();
}
std::u16string DownloadUIModel::GetWebDriveMessage(bool) const {
return std::u16string();
}
base::FilePath DownloadUIModel::GetFileNameToReportUser() const {
return base::FilePath();
}
base::FilePath DownloadUIModel::GetTargetFilePath() const {
return base::FilePath();
}
void DownloadUIModel::OpenDownload() {
NOTREACHED();
}
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::IsOpenWhenCompleteByPolicy() 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();
}
bool DownloadUIModel::HasUserGesture() const {
return false;
}
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:
case DownloadCommands::MAX:
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:
case DownloadCommands::LEARN_MORE_MIXED_CONTENT:
case DownloadCommands::DEEP_SCAN:
case DownloadCommands::BYPASS_DEEP_SCANNING:
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:
case DownloadCommands::MAX:
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::LEARN_MORE_MIXED_CONTENT:
case DownloadCommands::COPY_TO_CLIPBOARD:
case DownloadCommands::ANNOTATE:
case DownloadCommands::DEEP_SCAN:
case DownloadCommands::BYPASS_DEEP_SCANNING:
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:
case DownloadCommands::MAX:
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::LEARN_MORE_MIXED_CONTENT:
download_commands->GetBrowser()->OpenURL(content::OpenURLParams(
GURL(chrome::kMixedContentDownloadBlockingLearnMoreUrl),
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 BUILDFLAG(IS_CHROMEOS_ASH)
if (HasSupportedImageMimeType()) {
chromeos::NoteTakingHelper::Get()->LaunchAppForNewNote(
profile(), GetTargetFilePath());
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
break;
case DownloadCommands::DEEP_SCAN:
break;
case DownloadCommands::BYPASS_DEEP_SCANNING:
break;
}
}
#endif
std::string DownloadUIModel::GetMimeType() const {
return "text/html";
}
bool DownloadUIModel::IsExtensionDownload() const {
return false;
}
std::u16string DownloadUIModel::GetInProgressStatusText() const {
DCHECK_EQ(DownloadItem::IN_PROGRESS, GetState());
const auto web_drive = GetWebDriveName();
base::TimeDelta time_remaining;
// time_remaining is only known if the download isn't paused, and it isn't
// going to be rerouted to a web drive.
bool time_remaining_known =
(!IsPaused() && TimeRemaining(&time_remaining) && web_drive.empty());
// Indication of progress. (E.g.:"100/200 MB" or "100MB")
std::u16string 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 (web_drive.empty() && 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));
}
const auto completed_bytes = GetCompletedBytes();
const auto total_bytes = GetTotalBytes();
if (completed_bytes == 0) {
// Instead of displaying "0 B" we say "Starting..."
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING);
} else if (completed_bytes < total_bytes || total_bytes == 0) {
// In progress download with no known time left and non-zero completed
// bytes: "100/120 MB" or "100 MB"
return size_ratio;
} else if (web_drive.size()) {
// If all bytes of the file has been downloaded and it is being rerouted:
// "Sending to <WEB_DRIVE>..."
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_UPLOADING, web_drive);
} else {
return std::u16string();
}
}
std::u16string DownloadUIModel::GetCompletedStatusText() const {
if (GetFileExternallyRemoved()) {
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED);
}
const auto web_drive = GetWebDriveName();
if (web_drive.size()) {
// "Saved to <WEB_DRIVE>"
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_UPLOADED, web_drive);
}
return std::u16string();
}
// To clarify variable / method names in methods below that help form failure
// status messages:
// long & descriptive / short & concise
// "Failed - <STATE_DESCRIPTION / STATE_MESSAGE>"
// "Fail to save to <WEB_DRIVE> - <STATE_DESCRIPTION / STATE_MESSAGE>"
// < DESCRIPTION/STATUS_TEXT >
std::u16string DownloadUIModel::GetFailStateMessage(
offline_items_collection::FailState fail_state) const {
std::u16string state_msg;
if (fail_state != FailState::SERVER_FAILED ||
(state_msg = GetWebDriveMessage(/* verbose = */ false)).empty()) {
return OfflineItemUtils::GetFailStateMessage(fail_state);
}
return state_msg;
}
std::u16string DownloadUIModel::GetInterruptDescription() const {
std::u16string state_description;
const auto fail_state = GetLastFailState();
if (fail_state != FailState::SERVER_FAILED ||
(state_description = GetWebDriveMessage(/* verbose = */ true)).empty()) {
state_description = FailStateDescription(fail_state);
}
const auto web_drive = GetWebDriveName();
if (web_drive.empty()) {
// "Failed - <STATE_DESCRIPTION>"
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_INTERRUPTED,
state_description);
}
// else: file was rerouted. Formulate the message string accordingly.
// "Fail to save to <WEB_DRIVE> - <STATE_DESCRIPTION>"
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_UPLOAD_INTERRUPTED,
web_drive, state_description);
}
std::u16string DownloadUIModel::GetHistoryPageStatusText() const {
if (GetLastFailState() == FailState::SERVER_FAILED) {
// Display the full error description in case of server failure.
return GetInterruptDescription();
}
return GetStatusText();
}
std::u16string DownloadUIModel::GetInterruptedStatusText(
FailState fail_state) const {
auto state_msg = GetFailStateMessage(fail_state);
const auto web_drive = GetWebDriveName();
if (web_drive.empty()) {
// "Failed - <STATE_MESSAGE>"
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_INTERRUPTED,
state_msg);
}
// "Fail to save to <WEB_DRIVE> - <STATE_MESSAGE>"
return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_UPLOAD_INTERRUPTED,
web_drive, state_msg);
}
#if BUILDFLAG(FULL_SAFE_BROWSING)
void DownloadUIModel::CompleteSafeBrowsingScan() {}
#endif
bool DownloadUIModel::ShouldShowDropdown() const {
return true;
}