download_shelf.cc 7.55 KB
Newer Older
1 2 3 4 5 6
// Copyright (c) 2012 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_shelf.h"

7 8
#include "base/bind.h"
#include "base/callback.h"
9
#include "base/location.h"
10
#include "base/numerics/math_constants.h"
11
#include "base/single_thread_task_runner.h"
12
#include "base/strings/string_number_conversions.h"
13
#include "base/threading/thread_task_runner_handle.h"
14
#include "base/time/time.h"
enne's avatar
enne committed
15
#include "cc/paint/paint_flags.h"
16 17
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"
18 19 20 21
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_started_animation.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
22
#include "chrome/browser/themes/theme_properties.h"
23
#include "chrome/browser/ui/browser.h"
24
#include "chrome/browser/ui/tabs/tab_strip_model.h"
25 26 27 28
#include "content/public/browser/browser_context.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/web_contents.h"
29
#include "third_party/skia/include/core/SkPath.h"
30
#include "ui/base/resource/resource_bundle.h"
31
#include "ui/base/theme_provider.h"
32
#include "ui/gfx/animation/animation.h"
33 34
#include "ui/gfx/canvas.h"

35 36 37 38 39
using content::DownloadItem;

namespace {

// Delay before we show a transient download.
40
const int64_t kDownloadShowDelayInSeconds = 2;
41

42 43 44 45 46 47 48 49
// Get the opacity based on |animation_progress|, with values in [0.0, 1.0].
// Range of return value is [0, 255].
int GetOpacity(double animation_progress) {
  DCHECK(animation_progress >= 0 && animation_progress <= 1);

  // How many times to cycle the complete animation. This should be an odd
  // number so that the animation ends faded out.
  static const int kCompleteAnimationCycles = 5;
50 51
  double temp =
      ((animation_progress * kCompleteAnimationCycles) + 0.5) * base::kPiDouble;
52 53 54 55
  temp = sin(temp) / 2 + 0.5;
  return static_cast<int>(255.0 * temp);
}

56 57
} // namespace

58 59
DownloadShelf::DownloadShelf()
    : should_show_on_unhide_(false),
60
      is_hidden_(false),
61
      weak_ptr_factory_(this) {
62
}
63

64 65 66 67 68
DownloadShelf::~DownloadShelf() {}

// Download progress painting --------------------------------------------------

// static
69
void DownloadShelf::PaintDownloadProgress(
70
    gfx::Canvas* canvas,
71
    const ui::ThemeProvider& theme_provider,
72
    const base::TimeDelta& progress_time,
73
    int percent_done) {
74
  // Draw background (light blue circle).
75 76
  cc::PaintFlags bg_flags;
  bg_flags.setStyle(cc::PaintFlags::kFill_Style);
77
  SkColor indicator_color =
78
      theme_provider.GetColor(ThemeProperties::COLOR_TAB_THROBBER_SPINNING);
79 80
  bg_flags.setColor(SkColorSetA(indicator_color, 0x33));
  bg_flags.setAntiAlias(true);
81 82
  const SkScalar kCenterPoint = kProgressIndicatorSize / 2.f;
  SkPath bg;
83
  bg.addCircle(kCenterPoint, kCenterPoint, kCenterPoint);
84
  canvas->DrawPath(bg, bg_flags);
85 86 87 88 89

  // Calculate progress.
  SkScalar sweep_angle = 0.f;
  // Start at 12 o'clock.
  SkScalar start_pos = SkIntToScalar(270);
90
  if (percent_done < 0) {
91 92 93
    // For unknown size downloads, draw a 50 degree sweep that moves at
    // 0.08 degrees per millisecond.
    sweep_angle = 50.f;
94
    start_pos += static_cast<SkScalar>(progress_time.InMilliseconds() * 0.08);
95
  } else if (percent_done > 0) {
96
    sweep_angle = static_cast<SkScalar>(360 * percent_done / 100.0);
97 98
  }

99 100
  // Draw progress.
  SkPath progress;
101 102 103
  progress.addArc(
      SkRect::MakeLTRB(0, 0, kProgressIndicatorSize, kProgressIndicatorSize),
      start_pos, sweep_angle);
104 105 106 107 108 109
  cc::PaintFlags progress_flags;
  progress_flags.setColor(indicator_color);
  progress_flags.setStyle(cc::PaintFlags::kStroke_Style);
  progress_flags.setStrokeWidth(1.7f);
  progress_flags.setAntiAlias(true);
  canvas->DrawPath(progress, progress_flags);
110 111 112
}

// static
113 114
void DownloadShelf::PaintDownloadComplete(
    gfx::Canvas* canvas,
115
    const ui::ThemeProvider& theme_provider,
116
    double animation_progress) {
117 118
  // Start at full opacity, then loop back and forth five times before ending
  // at zero opacity.
pkasting's avatar
pkasting committed
119
  canvas->SaveLayerAlpha(GetOpacity(animation_progress));
120
  PaintDownloadProgress(canvas, theme_provider, base::TimeDelta(), 100);
pkasting's avatar
pkasting committed
121
  canvas->Restore();
122 123 124
}

// static
125 126
void DownloadShelf::PaintDownloadInterrupted(
    gfx::Canvas* canvas,
127
    const ui::ThemeProvider& theme_provider,
128
    double animation_progress) {
129 130
  // Start at zero opacity, then loop back and forth five times before ending
  // at full opacity.
131
  PaintDownloadComplete(canvas, theme_provider, 1.0 - animation_progress);
132 133 134 135 136 137 138 139
}

void DownloadShelf::AddDownload(DownloadItem* download) {
  DCHECK(download);
  if (DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete()) {
    // If we are going to remove the download from the shelf upon completion,
    // wait a few seconds to see if it completes quickly. If it's a small
    // download, then the user won't have time to interact with it.
140
    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
141
        FROM_HERE,
142 143
        base::BindOnce(&DownloadShelf::ShowDownloadById,
                       weak_ptr_factory_.GetWeakPtr(), download->GetId()),
144 145 146 147
        GetTransientDownloadShowDelay());
  } else {
    ShowDownload(download);
  }
148 149
}

150
void DownloadShelf::Open() {
151 152 153 154
  if (is_hidden_) {
    should_show_on_unhide_ = true;
    return;
  }
155
  DoOpen();
156 157
}

158
void DownloadShelf::Close(CloseReason reason) {
159 160 161 162
  if (is_hidden_) {
    should_show_on_unhide_ = false;
    return;
  }
163
  DoClose(reason);
164 165 166 167 168 169 170 171
}

void DownloadShelf::Hide() {
  if (is_hidden_)
    return;
  is_hidden_ = true;
  if (IsShowing()) {
    should_show_on_unhide_ = true;
172
    DoHide();
173 174 175 176 177 178 179 180 181
  }
}

void DownloadShelf::Unhide() {
  if (!is_hidden_)
    return;
  is_hidden_ = false;
  if (should_show_on_unhide_) {
    should_show_on_unhide_ = false;
182
    DoUnhide();
183 184
  }
}
185 186 187 188 189 190 191 192 193 194

base::TimeDelta DownloadShelf::GetTransientDownloadShowDelay() {
  return base::TimeDelta::FromSeconds(kDownloadShowDelayInSeconds);
}

content::DownloadManager* DownloadShelf::GetDownloadManager() {
  return content::BrowserContext::GetDownloadManager(browser()->profile());
}

void DownloadShelf::ShowDownload(DownloadItem* download) {
195
  if (download->GetState() == DownloadItem::COMPLETE &&
196 197
      DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete())
    return;
198 199 200
  if (!DownloadCoreServiceFactory::GetForBrowserContext(
           download->GetBrowserContext())
           ->IsShelfEnabled())
201 202 203 204
    return;

  if (is_hidden_)
    Unhide();
205
  Open();
206 207 208 209 210 211 212 213 214
  DoAddDownload(download);

  // browser() can be NULL for tests.
  if (!browser())
    return;

  // Show the download started animation if:
  // - Download started animation is enabled for this download. It is disabled
  //   for "Save As" downloads and extension installs, for example.
215
  // - The browser has an active visible WebContents. (browser isn't minimized,
216 217
  //   or running under a test etc.)
  // - Rich animations are enabled.
218 219
  content::WebContents* shelf_tab =
      browser()->tab_strip_model()->GetActiveWebContents();
220 221
  if (DownloadItemModel(download).ShouldShowDownloadStartedAnimation() &&
      shelf_tab &&
222
      platform_util::IsVisible(shelf_tab->GetNativeView()) &&
223
      gfx::Animation::ShouldRenderRichAnimation()) {
224 225 226 227
    DownloadStartedAnimation::Show(shelf_tab);
  }
}

228
void DownloadShelf::ShowDownloadById(int32_t download_id) {
229 230 231 232 233 234 235 236 237 238
  content::DownloadManager* download_manager = GetDownloadManager();
  if (!download_manager)
    return;

  DownloadItem* download = download_manager->GetDownload(download_id);
  if (!download)
    return;

  ShowDownload(download);
}