Commit 9e6c225b authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Reorganize code; no functional change.

* AnimateStateTransition() is never called; remove.
* OpenDownload(), Reenable(), DrawIcon(), UpdateColorsFromTheme(),
  GetErrorIconSize(), and ReleaseDropdown() are only referenced in one
  function apiece.  Inline them into their callers, which in many
  cases will provide future refactoring opportunities.  In a couple of
  cases (OnPaint() and ButtonPressed()) the callers are unwieldy as a
  result; these will be refactored in an upcoming CL.
* Reorder a few other functions to try and group related functions
  together more.
* Improve .h comments slightly.

Bug: none
Change-Id: Ic6801d70b3dadd1c696ee0d97fb8daf5b23f85c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2303863
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#789611}
parent 73a5fd25
...@@ -449,6 +449,8 @@ void DownloadItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { ...@@ -449,6 +449,8 @@ void DownloadItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
void DownloadItemView::ButtonPressed(views::Button* sender, void DownloadItemView::ButtonPressed(views::Button* sender,
const ui::Event& event) { const ui::Event& event) {
// TODO(pkasting): Refactor to simplify.
if (sender == open_now_button_) { if (sender == open_now_button_) {
OpenDownloadDuringAsyncScanning(); OpenDownloadDuringAsyncScanning();
return; return;
...@@ -506,7 +508,18 @@ void DownloadItemView::ButtonPressed(views::Button* sender, ...@@ -506,7 +508,18 @@ void DownloadItemView::ButtonPressed(views::Button* sender,
if (has_warning_label(mode_)) if (has_warning_label(mode_))
return; return;
complete_animation_.End(); complete_animation_.End();
OpenDownload();
// We're interested in how long it takes users to open downloads. If they
// open downloads super quickly, we should be concerned about clickjacking.
UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download",
base::Time::Now() - creation_time_);
// If this is still around for the next status update, it will be read.
announce_accessible_alert_soon_ = true;
// Calling download()->OpenDownload may delete this, so this must be
// the last thing we do.
model_->OpenDownload();
return; return;
} }
...@@ -575,10 +588,17 @@ void DownloadItemView::OnDownloadOpened() { ...@@ -575,10 +588,17 @@ void DownloadItemView::OnDownloadOpened() {
l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, filename_string)); l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, filename_string));
SetEnabled(false); SetEnabled(false);
const auto reenable = [](base::WeakPtr<DownloadItemView> view) {
if (!view)
return;
auto* label = view->file_name_label_;
label->SetTextStyle(views::style::STYLE_PRIMARY);
label->SetText(view->ElidedFilename());
view->SetEnabled(true);
};
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&DownloadItemView::Reenable, base::BindOnce(std::move(reenable), weak_ptr_factory_.GetWeakPtr()),
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(3)); base::TimeDelta::FromSeconds(3));
// Notify our parent. // Notify our parent.
...@@ -669,15 +689,106 @@ void DownloadItemView::OnPaintBackground(gfx::Canvas* canvas) { ...@@ -669,15 +689,106 @@ void DownloadItemView::OnPaintBackground(gfx::Canvas* canvas) {
} }
void DownloadItemView::OnPaint(gfx::Canvas* canvas) { void DownloadItemView::OnPaint(gfx::Canvas* canvas) {
// TODO(pkasting): Refactor to simplify.
OnPaintBackground(canvas); OnPaintBackground(canvas);
DrawIcon(canvas); bool use_new_warnings =
base::FeatureList::IsEnabled(safe_browsing::kUseNewDownloadWarnings);
bool show_warning_icon = mode_ != Mode::kNormal;
if (show_warning_icon && !use_new_warnings) {
int icon_x =
(base::i18n::IsRTL() ? width() - GetWarningIconSize() - kStartPadding
: kStartPadding);
int icon_y = (height() - GetWarningIconSize()) / 2;
canvas->DrawImageInt(GetWarningIcon(), icon_x, icon_y);
OnPaintBorder(canvas);
return;
}
// Paint download progress.
DownloadItem::DownloadState state = model_->GetState();
int progress_x = base::i18n::IsRTL()
? width() - kStartPadding - kProgressIndicatorSize
: kStartPadding;
int progress_y = (height() - kProgressIndicatorSize) / 2;
const gfx::RectF progress_bounds(
progress_x, progress_y, kProgressIndicatorSize, kProgressIndicatorSize);
const gfx::ImageSkia* current_icon = nullptr;
IconManager* im = g_browser_process->icon_manager();
gfx::Image* image_ptr = im->LookupIconFromFilepath(
model_->GetTargetFilePath(), IconLoader::SMALL);
if (image_ptr)
current_icon = image_ptr->ToImageSkia();
if (state == DownloadItem::IN_PROGRESS &&
!(use_new_warnings && show_warning_icon)) {
base::TimeDelta indeterminate_progress_time =
indeterminate_progress_time_elapsed_;
if (!model_->IsPaused()) {
indeterminate_progress_time +=
base::TimeTicks::Now() - indeterminate_progress_start_time_;
}
PaintDownloadProgress(canvas, progress_bounds, indeterminate_progress_time,
model_->PercentComplete());
} else if (complete_animation_.is_animating()) {
DCHECK_EQ(Mode::kNormal, mode_);
// Loop back and forth five times.
double start = 0, end = 5;
if (model_->GetState() == download::DownloadItem::INTERRUPTED)
std::swap(start, end);
const double value = gfx::Tween::DoubleValueBetween(
complete_animation_.GetCurrentValue(), start, end);
const double opacity = std::sin((value + 0.5) * base::kPiDouble) / 2 + 0.5;
canvas->SaveLayerAlpha(
static_cast<uint8_t>(gfx::Tween::IntValueBetween(opacity, 0, 255)));
PaintDownloadProgress(canvas, progress_bounds, base::TimeDelta(), 100);
canvas->Restore();
} else if (use_new_warnings) {
current_icon = &file_icon_;
}
if (current_icon) {
// Draw the icon image.
int kFiletypeIconOffset =
(kProgressIndicatorSize - current_icon->height()) / 2;
int icon_x = progress_x + kFiletypeIconOffset;
int icon_y = progress_y + kFiletypeIconOffset;
cc::PaintFlags flags;
// Use an alpha to make the image look disabled.
if (!GetEnabled())
flags.setAlpha(120);
canvas->DrawImageInt(*current_icon, icon_x, icon_y, flags);
// Overlay the danger icon if appropriate.
if (show_warning_icon && use_new_warnings) {
int icon_x =
(base::i18n::IsRTL() ? width() - GetWarningIconSize() - kStartPadding
: kStartPadding) +
kDangerIconOffset;
int icon_y = (height() - GetWarningIconSize()) / 2 + kDangerIconOffset;
canvas->DrawImageInt(GetWarningIcon(), icon_x, icon_y);
}
}
OnPaintBorder(canvas); OnPaintBorder(canvas);
} }
void DownloadItemView::OnThemeChanged() { void DownloadItemView::OnThemeChanged() {
views::View::OnThemeChanged(); views::View::OnThemeChanged();
UpdateColorsFromTheme();
SkColor background_color =
GetThemeProvider()->GetColor(ThemeProperties::COLOR_DOWNLOAD_SHELF);
file_name_label_->SetBackgroundColor(background_color);
status_label_->SetBackgroundColor(background_color);
shelf_->ConfigureButtonForTheme(open_now_button_);
shelf_->ConfigureButtonForTheme(save_button_);
shelf_->ConfigureButtonForTheme(discard_button_);
shelf_->ConfigureButtonForTheme(scan_button_);
SchedulePaint(); SchedulePaint();
UpdateDropdownButton(); UpdateDropdownButton();
} }
...@@ -882,188 +993,133 @@ void DownloadItemView::UpdateAccessibleAlertAndTimersForNormalMode() { ...@@ -882,188 +993,133 @@ void DownloadItemView::UpdateAccessibleAlertAndTimersForNormalMode() {
} }
} }
void DownloadItemView::OpenDownload() { void DownloadItemView::UpdateAccessibleAlert(
DCHECK(!is_download_warning(mode_)); const base::string16& accessible_alert_text,
// We're interested in how long it takes users to open downloads. If they bool is_last_update) {
// open downloads super quickly, we should be concerned about clickjacking. views::ViewAccessibility& ax = accessible_alert_->GetViewAccessibility();
UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download", ax.OverrideRole(ax::mojom::Role::kAlert);
base::Time::Now() - creation_time_); ax.OverrideName(accessible_alert_text);
if (is_last_update) {
// If this is still around for the next status update, it will be read. // Last update: stop the announcement interval timer and make the last
announce_accessible_alert_soon_ = true; // announcement immediately.
accessible_alert_timer_.AbandonAndStop();
// Calling download()->OpenDownload may delete this, so this must be AnnounceAccessibleAlert();
// the last thing we do. } else if (!accessible_alert_timer_.IsRunning()) {
model_->OpenDownload(); // First update: start the announcement interval timer and make the first
// announcement immediately.
accessible_alert_timer_.Start(FROM_HERE, kAccessibleAlertInterval, this,
&DownloadItemView::AnnounceAccessibleAlert);
AnnounceAccessibleAlert();
} else if (announce_accessible_alert_soon_) {
accessible_alert_timer_.Reset();
AnnounceAccessibleAlert();
}
} }
bool DownloadItemView::SubmitDownloadToFeedbackService( base::string16 DownloadItemView::GetInProgressAccessibleAlertText() {
DownloadCommands::Command download_command) { // If opening when complete or there is a warning, use the full status text.
#if BUILDFLAG(FULL_SAFE_BROWSING) if (model_->GetOpenWhenComplete() || has_warning_label(mode_))
safe_browsing::SafeBrowsingService* sb_service = return accessible_name_;
g_browser_process->safe_browsing_service();
if (!sb_service) // Prefer to announce the time remaining, if known.
return false; base::TimeDelta remaining;
safe_browsing::DownloadProtectionService* download_protection_service = if (model_->TimeRemaining(&remaining)) {
sb_service->download_protection_service(); // If complete, skip this round: a completion status update is coming soon.
if (!download_protection_service) if (remaining.is_zero())
return false; return base::string16();
// TODO(shaktisahu): Enable feedback service for offline item. base::string16 remaining_string =
if (model_->download()) { ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
return download_protection_service->MaybeBeginFeedbackForDownload( ui::TimeFormat::LENGTH_SHORT, remaining);
shelf_->browser()->profile(), model_->download(), download_command); return l10n_util::GetStringFUTF16(
IDS_DOWNLOAD_STATUS_TIME_REMAINING_ACCESSIBLE_ALERT, remaining_string);
} }
// WARNING: we are deleted at this point. Don't access 'this'.
return true;
#else
NOTREACHED();
return false;
#endif
}
void DownloadItemView::DrawIcon(gfx::Canvas* canvas) { // Time remaining is unknown, try to announce percent remaining.
bool use_new_warnings = if (model_->PercentComplete() > 0) {
base::FeatureList::IsEnabled(safe_browsing::kUseNewDownloadWarnings); DCHECK_LE(model_->PercentComplete(), 100);
bool show_warning_icon = mode_ != Mode::kNormal; return l10n_util::GetStringFUTF16Int(
if (show_warning_icon && !use_new_warnings) { IDS_DOWNLOAD_STATUS_PERCENT_COMPLETE_ACCESSIBLE_ALERT,
int icon_x = 100 - model_->PercentComplete());
(base::i18n::IsRTL() ? width() - GetWarningIconSize() - kStartPadding
: kStartPadding);
int icon_y = (height() - GetWarningIconSize()) / 2;
canvas->DrawImageInt(GetWarningIcon(), icon_x, icon_y);
return;
} }
// Paint download progress. // Percent remaining is also unknown, announce bytes to download.
DownloadItem::DownloadState state = model_->GetState(); base::string16 file_name =
int progress_x = base::i18n::IsRTL() model_->GetFileNameToReportUser().LossyDisplayName();
? width() - kStartPadding - kProgressIndicatorSize return l10n_util::GetStringFUTF16(
: kStartPadding; IDS_DOWNLOAD_STATUS_IN_PROGRESS_ACCESSIBLE_ALERT,
int progress_y = (height() - kProgressIndicatorSize) / 2; ui::FormatBytes(model_->GetTotalBytes()), file_name);
const gfx::RectF progress_bounds( }
progress_x, progress_y, kProgressIndicatorSize, kProgressIndicatorSize);
const gfx::ImageSkia* current_icon = nullptr; void DownloadItemView::AnnounceAccessibleAlert() {
IconManager* im = g_browser_process->icon_manager(); accessible_alert_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
gfx::Image* image_ptr = im->LookupIconFromFilepath( announce_accessible_alert_soon_ = false;
model_->GetTargetFilePath(), IconLoader::SMALL); }
if (image_ptr)
current_icon = image_ptr->ToImageSkia();
if (state == DownloadItem::IN_PROGRESS && void DownloadItemView::OnFileIconLoaded(IconLoader::IconSize icon_size,
!(use_new_warnings && show_warning_icon)) { gfx::Image icon_bitmap) {
base::TimeDelta indeterminate_progress_time = if (!icon_bitmap.IsEmpty()) {
indeterminate_progress_time_elapsed_; if (icon_size == IconLoader::NORMAL) {
if (!model_->IsPaused()) { // We want a 24x24 icon, but on Windows only 16x16 and 32x32 are
indeterminate_progress_time += // available. So take the NORMAL icon and downsize it.
base::TimeTicks::Now() - indeterminate_progress_start_time_; constexpr gfx::Size kFileIconSize(24, 24);
file_icon_ = gfx::ImageSkiaOperations::CreateResizedImage(
*icon_bitmap.ToImageSkia(), skia::ImageOperations::RESIZE_BEST,
kFileIconSize);
} }
PaintDownloadProgress(canvas, progress_bounds, indeterminate_progress_time, SchedulePaint();
model_->PercentComplete());
} else if (complete_animation_.is_animating()) {
DCHECK_EQ(Mode::kNormal, mode_);
// Loop back and forth five times.
double start = 0, end = 5;
if (model_->GetState() == download::DownloadItem::INTERRUPTED)
std::swap(start, end);
const double value = gfx::Tween::DoubleValueBetween(
complete_animation_.GetCurrentValue(), start, end);
const double opacity = std::sin((value + 0.5) * base::kPiDouble) / 2 + 0.5;
canvas->SaveLayerAlpha(
static_cast<uint8_t>(gfx::Tween::IntValueBetween(opacity, 0, 255)));
PaintDownloadProgress(canvas, progress_bounds, base::TimeDelta(), 100);
canvas->Restore();
} else if (use_new_warnings) {
current_icon = &file_icon_;
} }
}
if (!current_icon) void DownloadItemView::PaintDownloadProgress(
return; gfx::Canvas* canvas,
const gfx::RectF& bounds,
// Draw the icon image. const base::TimeDelta& indeterminate_progress_time,
int kFiletypeIconOffset = int percent_done) const {
(kProgressIndicatorSize - current_icon->height()) / 2; const SkColor color = GetThemeProvider()->GetColor(
int icon_x = progress_x + kFiletypeIconOffset; ThemeProperties::COLOR_TAB_THROBBER_SPINNING);
int icon_y = progress_y + kFiletypeIconOffset;
cc::PaintFlags flags;
// Use an alpha to make the image look disabled.
if (!GetEnabled())
flags.setAlpha(120);
canvas->DrawImageInt(*current_icon, icon_x, icon_y, flags);
// Overlay the danger icon if appropriate.
if (show_warning_icon && use_new_warnings) {
int icon_x =
(base::i18n::IsRTL() ? width() - GetWarningIconSize() - kStartPadding
: kStartPadding) +
kDangerIconOffset;
int icon_y = (height() - GetWarningIconSize()) / 2 + kDangerIconOffset;
canvas->DrawImageInt(GetWarningIcon(), icon_x, icon_y);
}
}
void DownloadItemView::UpdateColorsFromTheme() {
if (!GetThemeProvider())
return;
SkColor background_color =
GetThemeProvider()->GetColor(ThemeProperties::COLOR_DOWNLOAD_SHELF);
file_name_label_->SetBackgroundColor(background_color);
status_label_->SetBackgroundColor(background_color);
shelf_->ConfigureButtonForTheme(open_now_button_);
shelf_->ConfigureButtonForTheme(save_button_);
shelf_->ConfigureButtonForTheme(discard_button_);
shelf_->ConfigureButtonForTheme(scan_button_);
}
void DownloadItemView::UpdateDropdownButton() {
views::SetImageFromVectorIcon(
dropdown_button_,
dropdown_state_ == PUSHED ? kCaretDownIcon : kCaretUpIcon,
GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT));
}
void DownloadItemView::ShowContextMenuImpl(const gfx::Rect& rect,
ui::MenuSourceType source_type) {
// Similar hack as in MenuButton.
// We're about to show the menu from a mouse press. By showing from the
// mouse press event we block RootView in mouse dispatching. This also
// appears to cause RootView to get a mouse pressed BEFORE the mouse
// release is seen, which means RootView sends us another mouse press no
// matter where the user pressed. To force RootView to recalculate the
// mouse target during the mouse press we explicitly set the mouse handler
// to null.
static_cast<views::internal::RootView*>(GetWidget()->GetRootView())
->SetMouseHandler(nullptr);
if (!context_menu_.get()) // Draw background.
context_menu_ = std::make_unique<DownloadShelfContextMenuView>(this); cc::PaintFlags bg_flags;
context_menu_->Run(GetWidget()->GetTopLevelWidget(), rect, source_type, bg_flags.setColor(SkColorSetA(color, 0x33));
base::Bind(&DownloadItemView::ReleaseDropdown, bg_flags.setStyle(cc::PaintFlags::kFill_Style);
weak_ptr_factory_.GetWeakPtr())); bg_flags.setAntiAlias(true);
} canvas->DrawCircle(bounds.CenterPoint(), bounds.width() / 2, bg_flags);
void DownloadItemView::SetDropdownState(State new_state) { // Calculate progress.
if (new_state != dropdown_state_) { SkScalar start_pos = SkIntToScalar(270); // 12 o'clock
dropdown_button_->AnimateInkDrop(new_state == PUSHED SkScalar sweep_angle = SkDoubleToScalar(360 * percent_done / 100.0);
? views::InkDropState::ACTIVATED if (percent_done < 0) {
: views::InkDropState::DEACTIVATED, // Download size unknown. Draw a 50 degree sweep that moves at 80 degrees
nullptr); // per second.
dropdown_state_ = new_state; start_pos +=
UpdateDropdownButton(); SkDoubleToScalar(indeterminate_progress_time.InSecondsF() * 80);
SchedulePaint(); sweep_angle = SkIntToScalar(50);
} }
// Draw progress.
SkPath progress;
progress.addArc(gfx::RectFToSkRect(bounds), start_pos, sweep_angle);
cc::PaintFlags progress_flags;
progress_flags.setColor(color);
progress_flags.setStyle(cc::PaintFlags::kStroke_Style);
progress_flags.setStrokeWidth(1.7f);
progress_flags.setAntiAlias(true);
canvas->DrawPath(progress, progress_flags);
} }
gfx::ImageSkia DownloadItemView::GetWarningIcon() { gfx::ImageSkia DownloadItemView::GetWarningIcon() {
// TODO(drubery): Replace this with a constexpr variable when the new UX is
// fully launched.
const int error_icon_size =
base::FeatureList::IsEnabled(safe_browsing::kUseNewDownloadWarnings) ? 20
: 27;
switch (model_->GetDangerType()) { switch (model_->GetDangerType()) {
case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
if (safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile( if (safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
model()->profile()) model()->profile())
->IsUnderAdvancedProtection()) { ->IsUnderAdvancedProtection()) {
return gfx::CreateVectorIcon( return gfx::CreateVectorIcon(
vector_icons::kErrorIcon, GetErrorIconSize(), vector_icons::kErrorIcon, error_icon_size,
GetNativeTheme()->GetSystemColor( GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_AlertSeverityMedium)); ui::NativeTheme::kColorId_AlertSeverityMedium));
} }
...@@ -1085,13 +1141,13 @@ gfx::ImageSkia DownloadItemView::GetWarningIcon() { ...@@ -1085,13 +1141,13 @@ gfx::ImageSkia DownloadItemView::GetWarningIcon() {
case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING: case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING: case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING:
return gfx::CreateVectorIcon( return gfx::CreateVectorIcon(
vector_icons::kErrorIcon, GetErrorIconSize(), vector_icons::kErrorIcon, error_icon_size,
GetNativeTheme()->GetSystemColor( GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DefaultIconColor)); ui::NativeTheme::kColorId_DefaultIconColor));
case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING: case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
return gfx::CreateVectorIcon( return gfx::CreateVectorIcon(
vector_icons::kHelpIcon, GetErrorIconSize(), vector_icons::kHelpIcon, error_icon_size,
GetNativeTheme()->GetSystemColor( GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DefaultIconColor)); ui::NativeTheme::kColorId_DefaultIconColor));
...@@ -1114,7 +1170,7 @@ gfx::ImageSkia DownloadItemView::GetWarningIcon() { ...@@ -1114,7 +1170,7 @@ gfx::ImageSkia DownloadItemView::GetWarningIcon() {
ui::NativeTheme::kColorId_AlertSeverityHigh)); ui::NativeTheme::kColorId_AlertSeverityHigh));
case download::DownloadItem::MixedContentStatus::WARN: case download::DownloadItem::MixedContentStatus::WARN:
return gfx::CreateVectorIcon( return gfx::CreateVectorIcon(
vector_icons::kErrorIcon, GetErrorIconSize(), vector_icons::kErrorIcon, error_icon_size,
GetNativeTheme()->GetSystemColor( GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_AlertSeverityMedium)); ui::NativeTheme::kColorId_AlertSeverityMedium));
case download::DownloadItem::MixedContentStatus::UNKNOWN: case download::DownloadItem::MixedContentStatus::UNKNOWN:
...@@ -1128,6 +1184,31 @@ gfx::ImageSkia DownloadItemView::GetWarningIcon() { ...@@ -1128,6 +1184,31 @@ gfx::ImageSkia DownloadItemView::GetWarningIcon() {
return gfx::ImageSkia(); return gfx::ImageSkia();
} }
std::pair<base::string16, int> DownloadItemView::GetStatusTextAndStyle() const {
using DangerType = download::DownloadDangerType;
const auto type = model_->GetDangerType();
if (type == DangerType::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE) {
return {l10n_util::GetStringUTF16(IDS_PROMPT_DOWNLOAD_DEEP_SCANNED_SAFE),
STYLE_GREEN};
}
constexpr int kDangerous = IDS_PROMPT_DOWNLOAD_DEEP_SCANNED_OPENED_DANGEROUS;
if (type == DangerType::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS)
return {l10n_util::GetStringUTF16(kDangerous), STYLE_RED};
const GURL url = model_->GetOriginalURL().GetOrigin();
const base::string16 text =
(!model_->ShouldPromoteOrigin() || url.is_empty())
? model_->GetStatusText()
#if defined(OS_ANDROID)
// url_formatter::ElideUrl() doesn't exist on Android.
: base::string16();
#else
: url_formatter::ElideUrl(url, status_label_->font_list(),
kTextWidth);
#endif
return {text, views::style::STYLE_PRIMARY};
}
gfx::Size DownloadItemView::GetButtonSize() const { gfx::Size DownloadItemView::GetButtonSize() const {
gfx::Size size; gfx::Size size;
if (discard_button_->GetVisible()) if (discard_button_->GetVisible())
...@@ -1139,6 +1220,11 @@ gfx::Size DownloadItemView::GetButtonSize() const { ...@@ -1139,6 +1220,11 @@ gfx::Size DownloadItemView::GetButtonSize() const {
return size; return size;
} }
base::string16 DownloadItemView::ElidedFilename() {
return gfx::ElideFilename(model_->GetFileNameToReportUser(), font_list_,
kTextWidth);
}
int DownloadItemView::GetLabelWidth(const views::StyledLabel& label) const { int DownloadItemView::GetLabelWidth(const views::StyledLabel& label) const {
auto lines_for_width = [&label](int width) { auto lines_for_width = [&label](int width) {
return label.GetLayoutSizeInfoForWidth(width).line_sizes.size(); return label.GetLayoutSizeInfoForWidth(width).line_sizes.size();
...@@ -1162,177 +1248,77 @@ int DownloadItemView::GetLabelWidth(const views::StyledLabel& label) const { ...@@ -1162,177 +1248,77 @@ int DownloadItemView::GetLabelWidth(const views::StyledLabel& label) const {
std::move(lines_for_width)); std::move(lines_for_width));
} }
void DownloadItemView::Reenable() { void DownloadItemView::SetDropdownState(State new_state) {
file_name_label_->SetTextStyle(views::style::STYLE_PRIMARY); if (new_state != dropdown_state_) {
file_name_label_->SetText(ElidedFilename()); dropdown_button_->AnimateInkDrop(new_state == PUSHED
SetEnabled(true); // Triggers a repaint. ? views::InkDropState::ACTIVATED
} : views::InkDropState::DEACTIVATED,
nullptr);
void DownloadItemView::ReleaseDropdown() { dropdown_state_ = new_state;
SetDropdownState(NORMAL); UpdateDropdownButton();
// Make sure any new status from activating a context menu option is read.
announce_accessible_alert_soon_ = true;
}
void DownloadItemView::UpdateAccessibleAlert(
const base::string16& accessible_alert_text,
bool is_last_update) {
views::ViewAccessibility& ax = accessible_alert_->GetViewAccessibility();
ax.OverrideRole(ax::mojom::Role::kAlert);
ax.OverrideName(accessible_alert_text);
if (is_last_update) {
// Last update: stop the announcement interval timer and make the last
// announcement immediately.
accessible_alert_timer_.AbandonAndStop();
AnnounceAccessibleAlert();
} else if (!accessible_alert_timer_.IsRunning()) {
// First update: start the announcement interval timer and make the first
// announcement immediately.
accessible_alert_timer_.Start(FROM_HERE, kAccessibleAlertInterval, this,
&DownloadItemView::AnnounceAccessibleAlert);
AnnounceAccessibleAlert();
} else if (announce_accessible_alert_soon_) {
accessible_alert_timer_.Reset();
AnnounceAccessibleAlert();
}
}
base::string16 DownloadItemView::GetInProgressAccessibleAlertText() {
// If opening when complete or there is a warning, use the full status text.
if (model_->GetOpenWhenComplete() || has_warning_label(mode_))
return accessible_name_;
// Prefer to announce the time remaining, if known.
base::TimeDelta remaining;
if (model_->TimeRemaining(&remaining)) {
// If complete, skip this round: a completion status update is coming soon.
if (remaining.is_zero())
return base::string16();
base::string16 remaining_string =
ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
ui::TimeFormat::LENGTH_SHORT, remaining);
return l10n_util::GetStringFUTF16(
IDS_DOWNLOAD_STATUS_TIME_REMAINING_ACCESSIBLE_ALERT, remaining_string);
}
// Time remaining is unknown, try to announce percent remaining.
if (model_->PercentComplete() > 0) {
DCHECK_LE(model_->PercentComplete(), 100);
return l10n_util::GetStringFUTF16Int(
IDS_DOWNLOAD_STATUS_PERCENT_COMPLETE_ACCESSIBLE_ALERT,
100 - model_->PercentComplete());
}
// Percent remaining is also unknown, announce bytes to download.
base::string16 file_name =
model_->GetFileNameToReportUser().LossyDisplayName();
return l10n_util::GetStringFUTF16(
IDS_DOWNLOAD_STATUS_IN_PROGRESS_ACCESSIBLE_ALERT,
ui::FormatBytes(model_->GetTotalBytes()), file_name);
}
void DownloadItemView::AnnounceAccessibleAlert() {
accessible_alert_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
announce_accessible_alert_soon_ = false;
}
void DownloadItemView::OnFileIconLoaded(IconLoader::IconSize icon_size,
gfx::Image icon_bitmap) {
if (!icon_bitmap.IsEmpty()) {
if (icon_size == IconLoader::NORMAL) {
// We want a 24x24 icon, but on Windows only 16x16 and 32x32 are
// available. So take the NORMAL icon and downsize it.
constexpr gfx::Size kFileIconSize(24, 24);
file_icon_ = gfx::ImageSkiaOperations::CreateResizedImage(
*icon_bitmap.ToImageSkia(), skia::ImageOperations::RESIZE_BEST,
kFileIconSize);
}
SchedulePaint(); SchedulePaint();
} }
} }
void DownloadItemView::PaintDownloadProgress( void DownloadItemView::UpdateDropdownButton() {
gfx::Canvas* canvas, views::SetImageFromVectorIcon(
const gfx::RectF& bounds, dropdown_button_,
const base::TimeDelta& indeterminate_progress_time, dropdown_state_ == PUSHED ? kCaretDownIcon : kCaretUpIcon,
int percent_done) const { GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT));
const SkColor color = GetThemeProvider()->GetColor( }
ThemeProperties::COLOR_TAB_THROBBER_SPINNING);
// Draw background.
cc::PaintFlags bg_flags;
bg_flags.setColor(SkColorSetA(color, 0x33));
bg_flags.setStyle(cc::PaintFlags::kFill_Style);
bg_flags.setAntiAlias(true);
canvas->DrawCircle(bounds.CenterPoint(), bounds.width() / 2, bg_flags);
// Calculate progress. void DownloadItemView::ShowContextMenuImpl(const gfx::Rect& rect,
SkScalar start_pos = SkIntToScalar(270); // 12 o'clock ui::MenuSourceType source_type) {
SkScalar sweep_angle = SkDoubleToScalar(360 * percent_done / 100.0); // Similar hack as in MenuButtonController.
if (percent_done < 0) { // We're about to show the menu from a mouse press. By showing from the
// Download size unknown. Draw a 50 degree sweep that moves at 80 degrees // mouse press event we block RootView in mouse dispatching. This also
// per second. // appears to cause RootView to get a mouse pressed BEFORE the mouse
start_pos += // release is seen, which means RootView sends us another mouse press no
SkDoubleToScalar(indeterminate_progress_time.InSecondsF() * 80); // matter where the user pressed. To force RootView to recalculate the
sweep_angle = SkIntToScalar(50); // mouse target during the mouse press we explicitly set the mouse handler
} // to null.
static_cast<views::internal::RootView*>(GetWidget()->GetRootView())
->SetMouseHandler(nullptr);
// Draw progress. if (!context_menu_.get())
SkPath progress; context_menu_ = std::make_unique<DownloadShelfContextMenuView>(this);
progress.addArc(gfx::RectFToSkRect(bounds), start_pos, sweep_angle); const auto release_dropdown = [](DownloadItemView* view) {
cc::PaintFlags progress_flags; view->SetDropdownState(NORMAL);
progress_flags.setColor(color); // Make sure any new status from activating a context menu option is read.
progress_flags.setStyle(cc::PaintFlags::kStroke_Style); view->announce_accessible_alert_soon_ = true;
progress_flags.setStrokeWidth(1.7f); };
progress_flags.setAntiAlias(true); context_menu_->Run(
canvas->DrawPath(progress, progress_flags); GetWidget()->GetTopLevelWidget(), rect, source_type,
base::BindRepeating(std::move(release_dropdown), base::Unretained(this)));
} }
void DownloadItemView::AnimateStateTransition(State from, void DownloadItemView::OpenDownloadDuringAsyncScanning() {
State to, model_->CompleteSafeBrowsingScan();
gfx::SlideAnimation* animation) { model_->SetOpenWhenComplete(true);
if (from == NORMAL && to == HOT) {
animation->Show();
} else if (from == HOT && to == NORMAL) {
animation->Hide();
} else if (from != to) {
animation->Reset((to == HOT) ? 1.0 : 0.0);
}
} }
std::pair<base::string16, int> DownloadItemView::GetStatusTextAndStyle() const { bool DownloadItemView::SubmitDownloadToFeedbackService(
using DangerType = download::DownloadDangerType; DownloadCommands::Command download_command) {
const auto type = model_->GetDangerType(); #if BUILDFLAG(FULL_SAFE_BROWSING)
if (type == DangerType::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE) { safe_browsing::SafeBrowsingService* sb_service =
return {l10n_util::GetStringUTF16(IDS_PROMPT_DOWNLOAD_DEEP_SCANNED_SAFE), g_browser_process->safe_browsing_service();
STYLE_GREEN}; if (!sb_service)
return false;
safe_browsing::DownloadProtectionService* download_protection_service =
sb_service->download_protection_service();
if (!download_protection_service)
return false;
// TODO(shaktisahu): Enable feedback service for offline item.
if (model_->download()) {
return download_protection_service->MaybeBeginFeedbackForDownload(
shelf_->browser()->profile(), model_->download(), download_command);
} }
constexpr int kDangerous = IDS_PROMPT_DOWNLOAD_DEEP_SCANNED_OPENED_DANGEROUS; // WARNING: we are deleted at this point. Don't access 'this'.
if (type == DangerType::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS) return true;
return {l10n_util::GetStringUTF16(kDangerous), STYLE_RED};
const GURL url = model_->GetOriginalURL().GetOrigin();
const base::string16 text =
(!model_->ShouldPromoteOrigin() || url.is_empty())
? model_->GetStatusText()
#if defined(OS_ANDROID)
// url_formatter::ElideUrl() doesn't exist on Android.
: base::string16();
#else #else
: url_formatter::ElideUrl(url, status_label_->font_list(), NOTREACHED();
kTextWidth); return false;
#endif #endif
return {text, views::style::STYLE_PRIMARY};
}
base::string16 DownloadItemView::ElidedFilename() {
return gfx::ElideFilename(model_->GetFileNameToReportUser(), font_list_,
kTextWidth);
}
void DownloadItemView::OpenDownloadDuringAsyncScanning() {
model_->CompleteSafeBrowsingScan();
model_->SetOpenWhenComplete(true);
} }
// static // static
...@@ -1344,15 +1330,6 @@ int DownloadItemView::GetWarningIconSize() { ...@@ -1344,15 +1330,6 @@ int DownloadItemView::GetWarningIconSize() {
: 24; : 24;
} }
// static
int DownloadItemView::GetErrorIconSize() {
// TODO(drubery): Replace this method with a constexpr variable when the new
// UX is fully launched.
return base::FeatureList::IsEnabled(safe_browsing::kUseNewDownloadWarnings)
? 20
: 27;
}
void DownloadItemView::ConfirmDeepScanning() { void DownloadItemView::ConfirmDeepScanning() {
DownloadCommands(model_.get()).ExecuteCommand(DownloadCommands::DEEP_SCAN); DownloadCommands(model_.get()).ExecuteCommand(DownloadCommands::DEEP_SCAN);
} }
......
...@@ -148,49 +148,6 @@ class DownloadItemView : public views::View, ...@@ -148,49 +148,6 @@ class DownloadItemView : public views::View,
// Updates the accessible alert and timers for normal mode. // Updates the accessible alert and timers for normal mode.
void UpdateAccessibleAlertAndTimersForNormalMode(); void UpdateAccessibleAlertAndTimersForNormalMode();
void OpenDownload();
// Submits the downloaded file to the safebrowsing download feedback service.
// Returns whether submission was successful. Applies |download_command|, if
// submission fails.
bool SubmitDownloadToFeedbackService(
DownloadCommands::Command download_command);
void DrawIcon(gfx::Canvas* canvas);
// Update the button colors based on the current theme.
void UpdateColorsFromTheme();
void UpdateDropdownButton();
// Shows the context menu at the specified location. |point| is in the view's
// coordinate system.
void ShowContextMenuImpl(const gfx::Rect& rect,
ui::MenuSourceType source_type);
// Sets the state and triggers a repaint.
void SetDropdownState(State new_state);
// Returns the current warning icon (should only be called when the view is
// actually showing a warning).
gfx::ImageSkia GetWarningIcon();
// Sets |size| with the size of the Save and Discard buttons (they have the
// same size).
gfx::Size GetButtonSize() const;
// Returns either:
// * 200, if |label| can fit in one line given at most 200 DIP width.
// * The minimum width needed to display |label| on two lines.
int GetLabelWidth(const views::StyledLabel& label) const;
// Reenables the item after it has been disabled when a user clicked it to
// open the downloaded file.
void Reenable();
// Releases drop down button after showing a context menu.
void ReleaseDropdown();
// Update accessible status text. // Update accessible status text.
// If |is_last_update| is false, then a timer is used to notify screen readers // If |is_last_update| is false, then a timer is used to notify screen readers
// to speak the alert text on a regular interval. If |is_last_update| is true, // to speak the alert text on a regular interval. If |is_last_update| is true,
...@@ -217,28 +174,48 @@ class DownloadItemView : public views::View, ...@@ -217,28 +174,48 @@ class DownloadItemView : public views::View,
const base::TimeDelta& indeterminate_progress_time, const base::TimeDelta& indeterminate_progress_time,
int percent_done) const; int percent_done) const;
// Show/Hide/Reset |animation| based on the state transition specified by // When not in normal mode, returns the current help/warning/error icon.
// |from| and |to|. gfx::ImageSkia GetWarningIcon();
void AnimateStateTransition(State from,
State to,
gfx::SlideAnimation* animation);
// Returns the text and style to use for the status label. // Returns the text and style to use for the status label.
std::pair<base::string16, int> GetStatusTextAndStyle() const; std::pair<base::string16, int> GetStatusTextAndStyle() const;
// Returns the size of any button visible next to the label (all visible
// buttons are given the same size).
gfx::Size GetButtonSize() const;
// Returns the file name to report to user. It might be elided to fit into // Returns the file name to report to user. It might be elided to fit into
// the text width. // the text width.
base::string16 ElidedFilename(); base::string16 ElidedFilename();
// Returns either:
// * 200, if |label| can fit in one line given at most 200 DIP width.
// * The minimum width needed to display |label| on two lines.
int GetLabelWidth(const views::StyledLabel& label) const;
// Sets the state and triggers a repaint.
void SetDropdownState(State new_state);
// Sets |dropdown_button_| to have the correct image for the current state.
void UpdateDropdownButton();
// Shows the context menu at the specified location. |point| is in the view's
// coordinate system.
void ShowContextMenuImpl(const gfx::Rect& rect,
ui::MenuSourceType source_type);
// Opens a file while async scanning is still pending. // Opens a file while async scanning is still pending.
void OpenDownloadDuringAsyncScanning(); void OpenDownloadDuringAsyncScanning();
// Submits the downloaded file to the safebrowsing download feedback service.
// Applies |download_command| if submission succeeds. Returns whether
// submission was successful.
bool SubmitDownloadToFeedbackService(
DownloadCommands::Command download_command);
// Returns the height/width of the warning icon, in dp. // Returns the height/width of the warning icon, in dp.
static int GetWarningIconSize(); static int GetWarningIconSize();
// Returns the height/width of the error icon, in dp.
static int GetErrorIconSize();
// Starts deep scanning for this download item. // Starts deep scanning for this download item.
void ConfirmDeepScanning(); void ConfirmDeepScanning();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment