Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / download / download_shelf.cc
blob5f3f3cd4fbc0e68d4c9dfd823c1ee4720777dad5
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::TimeDelta& progress_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>(progress_time.InMilliseconds() * 0.08);
101 } else if (percent_done > 0) {
102 sweep_angle = static_cast<SkScalar>(360 * percent_done / 100.0);
105 // Draw progress.
106 SkPath progress;
107 progress.addArc(SkRect::MakeLTRB(kCenterPoint - kRadius,
108 kCenterPoint - kRadius,
109 kCenterPoint + kRadius,
110 kCenterPoint + kRadius),
111 start_pos, sweep_angle);
112 SkPaint progress_paint;
113 progress_paint.setColor(indicator_color);
114 progress_paint.setStyle(SkPaint::kStroke_Style);
115 progress_paint.setStrokeWidth(1.7f);
116 progress_paint.setAntiAlias(true);
117 canvas->DrawPath(progress, progress_paint);
120 // static
121 void DownloadShelf::PaintDownloadComplete(
122 gfx::Canvas* canvas,
123 const ui::ThemeProvider& theme_provider,
124 double animation_progress) {
125 // Start at full opacity, then loop back and forth five times before ending
126 // at zero opacity.
127 canvas->sk_canvas()->saveLayerAlpha(nullptr, GetOpacity(animation_progress));
128 PaintDownloadProgress(canvas, theme_provider, base::TimeDelta(), 100);
129 canvas->sk_canvas()->restore();
132 // static
133 void DownloadShelf::PaintDownloadInterrupted(
134 gfx::Canvas* canvas,
135 const ui::ThemeProvider& theme_provider,
136 double animation_progress) {
137 // Start at zero opacity, then loop back and forth five times before ending
138 // at full opacity.
139 PaintDownloadComplete(canvas, theme_provider, 1.0 - animation_progress);
142 void DownloadShelf::AddDownload(DownloadItem* download) {
143 DCHECK(download);
144 if (DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete()) {
145 // If we are going to remove the download from the shelf upon completion,
146 // wait a few seconds to see if it completes quickly. If it's a small
147 // download, then the user won't have time to interact with it.
148 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
149 FROM_HERE,
150 base::Bind(&DownloadShelf::ShowDownloadById,
151 weak_ptr_factory_.GetWeakPtr(), download->GetId()),
152 GetTransientDownloadShowDelay());
153 } else {
154 ShowDownload(download);
158 void DownloadShelf::Show() {
159 if (is_hidden_) {
160 should_show_on_unhide_ = true;
161 return;
163 DoShow();
166 void DownloadShelf::Close(CloseReason reason) {
167 if (is_hidden_) {
168 should_show_on_unhide_ = false;
169 return;
171 DoClose(reason);
174 void DownloadShelf::Hide() {
175 if (is_hidden_)
176 return;
177 is_hidden_ = true;
178 if (IsShowing()) {
179 should_show_on_unhide_ = true;
180 DoClose(AUTOMATIC);
184 void DownloadShelf::Unhide() {
185 if (!is_hidden_)
186 return;
187 is_hidden_ = false;
188 if (should_show_on_unhide_) {
189 should_show_on_unhide_ = false;
190 DoShow();
194 base::TimeDelta DownloadShelf::GetTransientDownloadShowDelay() {
195 return base::TimeDelta::FromSeconds(kDownloadShowDelayInSeconds);
198 content::DownloadManager* DownloadShelf::GetDownloadManager() {
199 return content::BrowserContext::GetDownloadManager(browser()->profile());
202 void DownloadShelf::ShowDownload(DownloadItem* download) {
203 if (download->GetState() == DownloadItem::COMPLETE &&
204 DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete())
205 return;
206 if (!DownloadServiceFactory::GetForBrowserContext(
207 download->GetBrowserContext())->IsShelfEnabled())
208 return;
210 if (is_hidden_)
211 Unhide();
212 Show();
213 DoAddDownload(download);
215 // browser() can be NULL for tests.
216 if (!browser())
217 return;
219 // Show the download started animation if:
220 // - Download started animation is enabled for this download. It is disabled
221 // for "Save As" downloads and extension installs, for example.
222 // - The browser has an active visible WebContents. (browser isn't minimized,
223 // or running under a test etc.)
224 // - Rich animations are enabled.
225 content::WebContents* shelf_tab =
226 browser()->tab_strip_model()->GetActiveWebContents();
227 if (DownloadItemModel(download).ShouldShowDownloadStartedAnimation() &&
228 shelf_tab &&
229 platform_util::IsVisible(shelf_tab->GetNativeView()) &&
230 gfx::Animation::ShouldRenderRichAnimation()) {
231 DownloadStartedAnimation::Show(shelf_tab);
235 void DownloadShelf::ShowDownloadById(int32 download_id) {
236 content::DownloadManager* download_manager = GetDownloadManager();
237 if (!download_manager)
238 return;
240 DownloadItem* download = download_manager->GetDownload(download_id);
241 if (!download)
242 return;
244 ShowDownload(download);