blob: cf47b9d592dee5f950d53c401ca5d05d77d2f40d [file] [log] [blame]
[email protected]1db76f22012-01-16 04:00:491// 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.
4
[email protected]3a8fb452013-08-06 22:23:595#define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first.
6
[email protected]1db76f22012-01-16 04:00:497#include "chrome/browser/download/download_shelf.h"
8
[email protected]3a8fb452013-08-06 22:23:599#include <cmath>
10
[email protected]8542e68d2013-01-10 04:33:4711#include "base/bind.h"
12#include "base/callback.h"
skyostil02598352015-06-12 12:37:2513#include "base/location.h"
14#include "base/single_thread_task_runner.h"
[email protected]3a8fb452013-08-06 22:23:5915#include "base/strings/string_number_conversions.h"
gabb15e19072016-05-11 20:45:4116#include "base/threading/thread_task_runner_handle.h"
estade6ef02ec82015-07-24 20:52:0817#include "base/time/time.h"
enne34f6084c2017-02-02 22:39:0818#include "cc/paint/paint_flags.h"
[email protected]8542e68d2013-01-10 04:33:4719#include "chrome/browser/download/download_item_model.h"
[email protected]423939d2013-07-31 20:00:0820#include "chrome/browser/download/download_service.h"
21#include "chrome/browser/download/download_service_factory.h"
[email protected]8542e68d2013-01-10 04:33:4722#include "chrome/browser/download/download_started_animation.h"
23#include "chrome/browser/platform_util.h"
24#include "chrome/browser/profiles/profile.h"
estade6ef02ec82015-07-24 20:52:0825#include "chrome/browser/themes/theme_properties.h"
[email protected]8542e68d2013-01-10 04:33:4726#include "chrome/browser/ui/browser.h"
[email protected]47ae23372013-01-29 01:50:4827#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]8542e68d2013-01-10 04:33:4728#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"
estade6ef02ec82015-07-24 20:52:0832#include "third_party/skia/include/core/SkPath.h"
[email protected]3a8fb452013-08-06 22:23:5933#include "ui/base/resource/resource_bundle.h"
estade6ef02ec82015-07-24 20:52:0834#include "ui/base/theme_provider.h"
[email protected]ffb15d12013-09-15 17:29:3035#include "ui/gfx/animation/animation.h"
[email protected]3a8fb452013-08-06 22:23:5936#include "ui/gfx/canvas.h"
[email protected]3a8fb452013-08-06 22:23:5937
[email protected]8542e68d2013-01-10 04:33:4738using content::DownloadItem;
39
40namespace {
41
42// Delay before we show a transient download.
avie4d7b6f2015-12-26 00:59:1843const int64_t kDownloadShowDelayInSeconds = 2;
[email protected]8542e68d2013-01-10 04:33:4744
[email protected]3a8fb452013-08-06 22:23:5945// Get the opacity based on |animation_progress|, with values in [0.0, 1.0].
46// Range of return value is [0, 255].
47int GetOpacity(double animation_progress) {
48 DCHECK(animation_progress >= 0 && animation_progress <= 1);
49
50 // How many times to cycle the complete animation. This should be an odd
51 // number so that the animation ends faded out.
52 static const int kCompleteAnimationCycles = 5;
53 double temp = animation_progress * kCompleteAnimationCycles * M_PI + M_PI_2;
54 temp = sin(temp) / 2 + 0.5;
55 return static_cast<int>(255.0 * temp);
56}
57
[email protected]8542e68d2013-01-10 04:33:4758} // namespace
59
[email protected]1db76f22012-01-16 04:00:4960DownloadShelf::DownloadShelf()
61 : should_show_on_unhide_(false),
[email protected]8542e68d2013-01-10 04:33:4762 is_hidden_(false),
[email protected]9c009092013-05-01 03:14:0963 weak_ptr_factory_(this) {
[email protected]8542e68d2013-01-10 04:33:4764}
[email protected]1db76f22012-01-16 04:00:4965
[email protected]3a8fb452013-08-06 22:23:5966DownloadShelf::~DownloadShelf() {}
67
[email protected]3a8fb452013-08-06 22:23:5968// Download progress painting --------------------------------------------------
69
[email protected]3a8fb452013-08-06 22:23:5970// static
estade2d381b02015-05-22 16:26:2171void DownloadShelf::PaintDownloadProgress(
[email protected]3a8fb452013-08-06 22:23:5972 gfx::Canvas* canvas,
estade6ef02ec82015-07-24 20:52:0873 const ui::ThemeProvider& theme_provider,
estadede2162f2015-08-26 19:57:5874 const base::TimeDelta& progress_time,
[email protected]3a8fb452013-08-06 22:23:5975 int percent_done) {
estade6ef02ec82015-07-24 20:52:0876 // Draw background (light blue circle).
enne32830822017-02-14 21:12:1877 cc::PaintFlags bg_flags;
78 bg_flags.setStyle(cc::PaintFlags::kFill_Style);
estade6ef02ec82015-07-24 20:52:0879 SkColor indicator_color =
estadeff6ab322015-12-01 03:07:5180 theme_provider.GetColor(ThemeProperties::COLOR_TAB_THROBBER_SPINNING);
enne32830822017-02-14 21:12:1881 bg_flags.setColor(SkColorSetA(indicator_color, 0x33));
82 bg_flags.setAntiAlias(true);
estade6ef02ec82015-07-24 20:52:0883 const SkScalar kCenterPoint = kProgressIndicatorSize / 2.f;
estade6ef02ec82015-07-24 20:52:0884 SkPath bg;
estade4eb03e52015-09-28 21:16:1885 bg.addCircle(kCenterPoint, kCenterPoint, kCenterPoint);
enne32830822017-02-14 21:12:1886 canvas->DrawPath(bg, bg_flags);
estade2d381b02015-05-22 16:26:2187
estade6ef02ec82015-07-24 20:52:0888 // Calculate progress.
89 SkScalar sweep_angle = 0.f;
90 // Start at 12 o'clock.
91 SkScalar start_pos = SkIntToScalar(270);
[email protected]3a8fb452013-08-06 22:23:5992 if (percent_done < 0) {
estade6ef02ec82015-07-24 20:52:0893 // For unknown size downloads, draw a 50 degree sweep that moves at
94 // 0.08 degrees per millisecond.
95 sweep_angle = 50.f;
estadede2162f2015-08-26 19:57:5896 start_pos += static_cast<SkScalar>(progress_time.InMilliseconds() * 0.08);
[email protected]3a8fb452013-08-06 22:23:5997 } else if (percent_done > 0) {
estade6ef02ec82015-07-24 20:52:0898 sweep_angle = static_cast<SkScalar>(360 * percent_done / 100.0);
[email protected]3a8fb452013-08-06 22:23:5999 }
100
estade6ef02ec82015-07-24 20:52:08101 // Draw progress.
102 SkPath progress;
estade4eb03e52015-09-28 21:16:18103 progress.addArc(
104 SkRect::MakeLTRB(0, 0, kProgressIndicatorSize, kProgressIndicatorSize),
105 start_pos, sweep_angle);
enne32830822017-02-14 21:12:18106 cc::PaintFlags progress_flags;
107 progress_flags.setColor(indicator_color);
108 progress_flags.setStyle(cc::PaintFlags::kStroke_Style);
109 progress_flags.setStrokeWidth(1.7f);
110 progress_flags.setAntiAlias(true);
111 canvas->DrawPath(progress, progress_flags);
[email protected]3a8fb452013-08-06 22:23:59112}
113
114// static
[email protected]080572c2014-07-16 04:21:21115void DownloadShelf::PaintDownloadComplete(
116 gfx::Canvas* canvas,
estade6ef02ec82015-07-24 20:52:08117 const ui::ThemeProvider& theme_provider,
estade2d381b02015-05-22 16:26:21118 double animation_progress) {
[email protected]3a8fb452013-08-06 22:23:59119 // Start at full opacity, then loop back and forth five times before ending
120 // at zero opacity.
pkastingb822f552015-11-04 01:51:42121 canvas->SaveLayerAlpha(GetOpacity(animation_progress));
estadede2162f2015-08-26 19:57:58122 PaintDownloadProgress(canvas, theme_provider, base::TimeDelta(), 100);
pkastingb822f552015-11-04 01:51:42123 canvas->Restore();
[email protected]3a8fb452013-08-06 22:23:59124}
125
126// static
[email protected]080572c2014-07-16 04:21:21127void DownloadShelf::PaintDownloadInterrupted(
128 gfx::Canvas* canvas,
estade6ef02ec82015-07-24 20:52:08129 const ui::ThemeProvider& theme_provider,
estade2d381b02015-05-22 16:26:21130 double animation_progress) {
[email protected]3a8fb452013-08-06 22:23:59131 // Start at zero opacity, then loop back and forth five times before ending
132 // at full opacity.
estade6ef02ec82015-07-24 20:52:08133 PaintDownloadComplete(canvas, theme_provider, 1.0 - animation_progress);
[email protected]8542e68d2013-01-10 04:33:47134}
135
136void DownloadShelf::AddDownload(DownloadItem* download) {
137 DCHECK(download);
138 if (DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete()) {
139 // If we are going to remove the download from the shelf upon completion,
140 // wait a few seconds to see if it completes quickly. If it's a small
141 // download, then the user won't have time to interact with it.
skyostil02598352015-06-12 12:37:25142 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
[email protected]8542e68d2013-01-10 04:33:47143 FROM_HERE,
144 base::Bind(&DownloadShelf::ShowDownloadById,
skyostil02598352015-06-12 12:37:25145 weak_ptr_factory_.GetWeakPtr(), download->GetId()),
[email protected]8542e68d2013-01-10 04:33:47146 GetTransientDownloadShowDelay());
147 } else {
148 ShowDownload(download);
149 }
[email protected]1db76f22012-01-16 04:00:49150}
151
sdy75789252017-02-17 17:25:57152void DownloadShelf::Open() {
[email protected]1db76f22012-01-16 04:00:49153 if (is_hidden_) {
154 should_show_on_unhide_ = true;
155 return;
156 }
sdy75789252017-02-17 17:25:57157 DoOpen();
[email protected]1db76f22012-01-16 04:00:49158}
159
[email protected]6fab1032013-04-01 17:29:17160void DownloadShelf::Close(CloseReason reason) {
[email protected]1db76f22012-01-16 04:00:49161 if (is_hidden_) {
162 should_show_on_unhide_ = false;
163 return;
164 }
[email protected]6fab1032013-04-01 17:29:17165 DoClose(reason);
[email protected]1db76f22012-01-16 04:00:49166}
167
168void DownloadShelf::Hide() {
169 if (is_hidden_)
170 return;
171 is_hidden_ = true;
172 if (IsShowing()) {
173 should_show_on_unhide_ = true;
sdy75789252017-02-17 17:25:57174 DoHide();
[email protected]1db76f22012-01-16 04:00:49175 }
176}
177
178void DownloadShelf::Unhide() {
179 if (!is_hidden_)
180 return;
181 is_hidden_ = false;
182 if (should_show_on_unhide_) {
183 should_show_on_unhide_ = false;
sdy75789252017-02-17 17:25:57184 DoUnhide();
[email protected]1db76f22012-01-16 04:00:49185 }
186}
[email protected]8542e68d2013-01-10 04:33:47187
188base::TimeDelta DownloadShelf::GetTransientDownloadShowDelay() {
189 return base::TimeDelta::FromSeconds(kDownloadShowDelayInSeconds);
190}
191
192content::DownloadManager* DownloadShelf::GetDownloadManager() {
[email protected]8542e68d2013-01-10 04:33:47193 return content::BrowserContext::GetDownloadManager(browser()->profile());
194}
195
196void DownloadShelf::ShowDownload(DownloadItem* download) {
[email protected]9f259e12013-05-24 23:41:11197 if (download->GetState() == DownloadItem::COMPLETE &&
[email protected]423939d2013-07-31 20:00:08198 DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete())
[email protected]8542e68d2013-01-10 04:33:47199 return;
[email protected]423939d2013-07-31 20:00:08200 if (!DownloadServiceFactory::GetForBrowserContext(
201 download->GetBrowserContext())->IsShelfEnabled())
202 return;
[email protected]8542e68d2013-01-10 04:33:47203
204 if (is_hidden_)
205 Unhide();
sdy75789252017-02-17 17:25:57206 Open();
[email protected]8542e68d2013-01-10 04:33:47207 DoAddDownload(download);
208
209 // browser() can be NULL for tests.
210 if (!browser())
211 return;
212
213 // Show the download started animation if:
214 // - Download started animation is enabled for this download. It is disabled
215 // for "Save As" downloads and extension installs, for example.
[email protected]47ae23372013-01-29 01:50:48216 // - The browser has an active visible WebContents. (browser isn't minimized,
[email protected]8542e68d2013-01-10 04:33:47217 // or running under a test etc.)
218 // - Rich animations are enabled.
[email protected]47ae23372013-01-29 01:50:48219 content::WebContents* shelf_tab =
220 browser()->tab_strip_model()->GetActiveWebContents();
[email protected]8542e68d2013-01-10 04:33:47221 if (DownloadItemModel(download).ShouldShowDownloadStartedAnimation() &&
222 shelf_tab &&
[email protected]fc2b46b2014-05-03 16:33:45223 platform_util::IsVisible(shelf_tab->GetNativeView()) &&
[email protected]ffb15d12013-09-15 17:29:30224 gfx::Animation::ShouldRenderRichAnimation()) {
[email protected]8542e68d2013-01-10 04:33:47225 DownloadStartedAnimation::Show(shelf_tab);
226 }
227}
228
avie4d7b6f2015-12-26 00:59:18229void DownloadShelf::ShowDownloadById(int32_t download_id) {
[email protected]8542e68d2013-01-10 04:33:47230 content::DownloadManager* download_manager = GetDownloadManager();
231 if (!download_manager)
232 return;
233
234 DownloadItem* download = download_manager->GetDownload(download_id);
235 if (!download)
236 return;
237
238 ShowDownload(download);
239}