Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / download / download_shelf.cc
bloba5d3ff37903bd116162040136f2b112f4b0d1170
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 #define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first.
7 #include "chrome/browser/download/download_shelf.h"
9 #include <cmath>
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/location.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/download/download_item_model.h"
19 #include "chrome/browser/download/download_service.h"
20 #include "chrome/browser/download/download_service_factory.h"
21 #include "chrome/browser/download/download_started_animation.h"
22 #include "chrome/browser/platform_util.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/themes/theme_properties.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
27 #include "chrome/grit/locale_settings.h"
28 #include "content/public/browser/browser_context.h"
29 #include "content/public/browser/download_item.h"
30 #include "content/public/browser/download_manager.h"
31 #include "content/public/browser/web_contents.h"
32 #include "grit/theme_resources.h"
33 #include "third_party/skia/include/core/SkPaint.h"
34 #include "third_party/skia/include/core/SkPath.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/resource/resource_bundle.h"
37 #include "ui/base/theme_provider.h"
38 #include "ui/gfx/animation/animation.h"
39 #include "ui/gfx/canvas.h"
41 using content::DownloadItem;
43 namespace {
45 // Delay before we show a transient download.
46 const int64 kDownloadShowDelayInSeconds = 2;
48 // Get the opacity based on |animation_progress|, with values in [0.0, 1.0].
49 // Range of return value is [0, 255].
50 int GetOpacity(double animation_progress) {
51 DCHECK(animation_progress >= 0 && animation_progress <= 1);
53 // How many times to cycle the complete animation. This should be an odd
54 // number so that the animation ends faded out.
55 static const int kCompleteAnimationCycles = 5;
56 double temp = animation_progress * kCompleteAnimationCycles * M_PI + M_PI_2;
57 temp = sin(temp) / 2 + 0.5;
58 return static_cast<int>(255.0 * temp);
61 } // namespace
63 DownloadShelf::DownloadShelf()
64 : should_show_on_unhide_(false),
65 is_hidden_(false),
66 weak_ptr_factory_(this) {
69 DownloadShelf::~DownloadShelf() {}
71 // Download progress painting --------------------------------------------------
73 // static
74 void DownloadShelf::PaintDownloadProgress(
75 gfx::Canvas* canvas,
76 const ui::ThemeProvider& theme_provider,
77 const base::TimeTicks& progress_start_time,
78 int percent_done) {
79 // Draw background (light blue circle).
80 SkPaint bg_paint;
81 bg_paint.setStyle(SkPaint::kFill_Style);
82 SkColor indicator_color =
83 theme_provider.GetColor(ThemeProperties::COLOR_THROBBER_SPINNING);
84 bg_paint.setColor(SkColorSetA(indicator_color, 0x33));
85 bg_paint.setAntiAlias(true);
86 const SkScalar kCenterPoint = kProgressIndicatorSize / 2.f;
87 const SkScalar kRadius = 12.5f;
88 SkPath bg;
89 bg.addCircle(kCenterPoint, kCenterPoint, kRadius);
90 canvas->DrawPath(bg, bg_paint);
92 // Calculate progress.
93 SkScalar sweep_angle = 0.f;
94 // Start at 12 o'clock.
95 SkScalar start_pos = SkIntToScalar(270);
96 if (percent_done < 0) {
97 // For unknown size downloads, draw a 50 degree sweep that moves at
98 // 0.08 degrees per millisecond.
99 sweep_angle = 50.f;
100 start_pos += static_cast<SkScalar>(
101 (base::TimeTicks::Now() - progress_start_time).InMilliseconds() * 0.08);
102 } else if (percent_done > 0) {
103 sweep_angle = static_cast<SkScalar>(360 * percent_done / 100.0);
106 // Draw progress.
107 SkPath progress;
108 progress.addArc(SkRect::MakeLTRB(kCenterPoint - kRadius,
109 kCenterPoint - kRadius,
110 kCenterPoint + kRadius,
111 kCenterPoint + kRadius),
112 start_pos, sweep_angle);
113 SkPaint progress_paint;
114 progress_paint.setColor(indicator_color);
115 progress_paint.setStyle(SkPaint::kStroke_Style);
116 progress_paint.setStrokeWidth(1.7f);
117 progress_paint.setAntiAlias(true);
118 canvas->DrawPath(progress, progress_paint);
121 // static
122 void DownloadShelf::PaintDownloadComplete(
123 gfx::Canvas* canvas,
124 const ui::ThemeProvider& theme_provider,
125 double animation_progress) {
126 // Start at full opacity, then loop back and forth five times before ending
127 // at zero opacity.
128 canvas->sk_canvas()->saveLayerAlpha(nullptr, GetOpacity(animation_progress));
129 PaintDownloadProgress(canvas, theme_provider, base::TimeTicks(), 100);
130 canvas->sk_canvas()->restore();
133 // static
134 void DownloadShelf::PaintDownloadInterrupted(
135 gfx::Canvas* canvas,
136 const ui::ThemeProvider& theme_provider,
137 double animation_progress) {
138 // Start at zero opacity, then loop back and forth five times before ending
139 // at full opacity.
140 PaintDownloadComplete(canvas, theme_provider, 1.0 - animation_progress);
143 void DownloadShelf::AddDownload(DownloadItem* download) {
144 DCHECK(download);
145 if (DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete()) {
146 // If we are going to remove the download from the shelf upon completion,
147 // wait a few seconds to see if it completes quickly. If it's a small
148 // download, then the user won't have time to interact with it.
149 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
150 FROM_HERE,
151 base::Bind(&DownloadShelf::ShowDownloadById,
152 weak_ptr_factory_.GetWeakPtr(), download->GetId()),
153 GetTransientDownloadShowDelay());
154 } else {
155 ShowDownload(download);
159 void DownloadShelf::Show() {
160 if (is_hidden_) {
161 should_show_on_unhide_ = true;
162 return;
164 DoShow();
167 void DownloadShelf::Close(CloseReason reason) {
168 if (is_hidden_) {
169 should_show_on_unhide_ = false;
170 return;
172 DoClose(reason);
175 void DownloadShelf::Hide() {
176 if (is_hidden_)
177 return;
178 is_hidden_ = true;
179 if (IsShowing()) {
180 should_show_on_unhide_ = true;
181 DoClose(AUTOMATIC);
185 void DownloadShelf::Unhide() {
186 if (!is_hidden_)
187 return;
188 is_hidden_ = false;
189 if (should_show_on_unhide_) {
190 should_show_on_unhide_ = false;
191 DoShow();
195 base::TimeDelta DownloadShelf::GetTransientDownloadShowDelay() {
196 return base::TimeDelta::FromSeconds(kDownloadShowDelayInSeconds);
199 content::DownloadManager* DownloadShelf::GetDownloadManager() {
200 return content::BrowserContext::GetDownloadManager(browser()->profile());
203 void DownloadShelf::ShowDownload(DownloadItem* download) {
204 if (download->GetState() == DownloadItem::COMPLETE &&
205 DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete())
206 return;
207 if (!DownloadServiceFactory::GetForBrowserContext(
208 download->GetBrowserContext())->IsShelfEnabled())
209 return;
211 if (is_hidden_)
212 Unhide();
213 Show();
214 DoAddDownload(download);
216 // browser() can be NULL for tests.
217 if (!browser())
218 return;
220 // Show the download started animation if:
221 // - Download started animation is enabled for this download. It is disabled
222 // for "Save As" downloads and extension installs, for example.
223 // - The browser has an active visible WebContents. (browser isn't minimized,
224 // or running under a test etc.)
225 // - Rich animations are enabled.
226 content::WebContents* shelf_tab =
227 browser()->tab_strip_model()->GetActiveWebContents();
228 if (DownloadItemModel(download).ShouldShowDownloadStartedAnimation() &&
229 shelf_tab &&
230 platform_util::IsVisible(shelf_tab->GetNativeView()) &&
231 gfx::Animation::ShouldRenderRichAnimation()) {
232 DownloadStartedAnimation::Show(shelf_tab);
236 void DownloadShelf::ShowDownloadById(int32 download_id) {
237 content::DownloadManager* download_manager = GetDownloadManager();
238 if (!download_manager)
239 return;
241 DownloadItem* download = download_manager->GetDownload(download_id);
242 if (!download)
243 return;
245 ShowDownload(download);