15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#define _USE_MATH_DEFINES  // For VC++ to get M_PI. This has to be first.
63240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_shelf.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include <cmath>
103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/strings/string_number_conversions.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/download/download_item_model.h"
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/download/download_service.h"
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/download/download_service_factory.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/download/download_started_animation.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/platform_util.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/locale_settings.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_context.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/download_item.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/download_manager.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents.h"
283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "grit/theme_resources.h"
293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ui/base/l10n/l10n_util.h"
303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ui/base/resource/resource_bundle.h"
31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation.h"
323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ui/gfx/canvas.h"
333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ui/gfx/image/image_skia.h"
343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::DownloadItem;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Delay before we show a transient download.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int64 kDownloadShowDelayInSeconds = 2;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Get the opacity based on |animation_progress|, with values in [0.0, 1.0].
433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Range of return value is [0, 255].
443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint GetOpacity(double animation_progress) {
453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  DCHECK(animation_progress >= 0 && animation_progress <= 1);
463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // How many times to cycle the complete animation. This should be an odd
483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // number so that the animation ends faded out.
493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  static const int kCompleteAnimationCycles = 5;
503240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  double temp = animation_progress * kCompleteAnimationCycles * M_PI + M_PI_2;
513240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  temp = sin(temp) / 2 + 0.5;
523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return static_cast<int>(255.0 * temp);
533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadShelf::DownloadShelf()
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : should_show_on_unhide_(false),
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_hidden_(false),
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochDownloadShelf::~DownloadShelf() {}
643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
653240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// static
663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint DownloadShelf::GetBigProgressIconSize() {
673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  static int big_progress_icon_size = 0;
683240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (big_progress_icon_size == 0) {
693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    base::string16 locale_size_str =
703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        l10n_util::GetStringUTF16(IDS_DOWNLOAD_BIG_PROGRESS_SIZE);
713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    bool rc = base::StringToInt(locale_size_str, &big_progress_icon_size);
723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (!rc || big_progress_icon_size < kBigProgressIconSize) {
733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      NOTREACHED();
743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      big_progress_icon_size = kBigProgressIconSize;
753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return big_progress_icon_size;
793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// static
823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint DownloadShelf::GetBigProgressIconOffset() {
833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return (GetBigProgressIconSize() - kBigIconSize) / 2;
843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Download progress painting --------------------------------------------------
873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Common images used for download progress animations. We load them once the
893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// first time we do a progress paint, then reuse them as they are always the
903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// same.
913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochgfx::ImageSkia* g_foreground_16 = NULL;
923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochgfx::ImageSkia* g_background_16 = NULL;
933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochgfx::ImageSkia* g_foreground_32 = NULL;
943240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochgfx::ImageSkia* g_background_32 = NULL;
953240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// static
973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid DownloadShelf::PaintCustomDownloadProgress(
983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    gfx::Canvas* canvas,
993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    const gfx::ImageSkia& background_image,
1003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    const gfx::ImageSkia& foreground_image,
1013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    int image_size,
1023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    const gfx::Rect& bounds,
1033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    int start_angle,
1043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    int percent_done) {
1053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Draw the background progress image.
1063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->DrawImageInt(background_image,
1073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       bounds.x(),
1083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       bounds.y());
1093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Layer the foreground progress image in an arc proportional to the download
1113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // progress. The arc grows clockwise, starting in the midnight position, as
1123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // the download progresses. However, if the download does not have known total
1133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // size (the server didn't give us one), then we just spin an arc around until
1143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // we're done.
1153240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  float sweep_angle = 0.0;
1163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  float start_pos = static_cast<float>(kStartAngleDegrees);
1173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (percent_done < 0) {
1183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    sweep_angle = kUnknownAngleDegrees;
1193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    start_pos = static_cast<float>(start_angle);
1203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  } else if (percent_done > 0) {
1213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    sweep_angle = static_cast<float>(kMaxDegrees / 100.0 * percent_done);
1223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
1233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Set up an arc clipping region for the foreground image. Don't bother using
1253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // a clipping region if it would round to 360 (really 0) degrees, since that
1263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // would eliminate the foreground completely and be quite confusing (it would
1273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // look like 0% complete when it should be almost 100%).
1283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->Save();
1293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (sweep_angle < static_cast<float>(kMaxDegrees - 1)) {
1303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    SkRect oval;
1313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    oval.set(SkIntToScalar(bounds.x()),
1323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch             SkIntToScalar(bounds.y()),
1333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch             SkIntToScalar(bounds.x() + image_size),
1343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch             SkIntToScalar(bounds.y() + image_size));
1353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    SkPath path;
1363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    path.arcTo(oval,
1373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch               SkFloatToScalar(start_pos),
1383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch               SkFloatToScalar(sweep_angle), false);
1393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    path.lineTo(SkIntToScalar(bounds.x() + image_size / 2),
1403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                SkIntToScalar(bounds.y() + image_size / 2));
1413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    // gfx::Canvas::ClipPath does not provide for anti-aliasing.
1433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    canvas->sk_canvas()->clipPath(path, SkRegion::kIntersect_Op, true);
1443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
1453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->DrawImageInt(foreground_image,
1473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       bounds.x(),
1483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       bounds.y());
1493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->Restore();
1503240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
1513240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// static
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid DownloadShelf::PaintDownloadProgress(
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Canvas* canvas,
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const BoundsAdjusterCallback& rtl_mirror,
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int origin_x,
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int origin_y,
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int start_angle,
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int percent_done,
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PaintDownloadProgressSize size) {
1613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Load up our common images.
1623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (!g_background_16) {
1633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_foreground_16 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16);
1653240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_background_16 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_BACKGROUND_16);
1663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_foreground_32 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32);
1673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_background_32 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_BACKGROUND_32);
1683240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK_EQ(g_foreground_16->width(), g_background_16->width());
1693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK_EQ(g_foreground_16->height(), g_background_16->height());
1703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK_EQ(g_foreground_32->width(), g_background_32->width());
1713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    DCHECK_EQ(g_foreground_32->height(), g_background_32->height());
1723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
1733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::ImageSkia* background =
1753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      (size == BIG) ? g_background_32 : g_background_16;
1763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::ImageSkia* foreground =
1773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      (size == BIG) ? g_foreground_32 : g_foreground_16;
1783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  const int kProgressIconSize =
1803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      (size == BIG) ? kBigProgressIconSize : kSmallProgressIconSize;
1813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // We start by storing the bounds of the images so that it is easy to mirror
1833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // the bounds if the UI layout is RTL.
1843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::Rect bounds(origin_x, origin_y,
1853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                   background->width(), background->height());
1863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Mirror the positions if necessary.
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  rtl_mirror.Run(&bounds);
1893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Draw the background progress image.
1913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->DrawImageInt(*background,
1923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       bounds.x(),
1933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       bounds.y());
1943240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
1953240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PaintCustomDownloadProgress(canvas,
1963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                              *background,
1973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                              *foreground,
1983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                              kProgressIconSize,
1993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                              bounds,
2003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                              start_angle,
2013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                              percent_done);
2023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
2033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// static
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid DownloadShelf::PaintDownloadComplete(
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Canvas* canvas,
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const BoundsAdjusterCallback& rtl_mirror,
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int origin_x,
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int origin_y,
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    double animation_progress,
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PaintDownloadProgressSize size) {
2123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Load up our common images.
2133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (!g_foreground_16) {
2143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
2153240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_foreground_16 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16);
2163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_foreground_32 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32);
2173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
2183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::ImageSkia* complete = (size == BIG) ? g_foreground_32 : g_foreground_16;
2203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::Rect complete_bounds(origin_x, origin_y,
2223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                            complete->width(), complete->height());
2233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Mirror the positions if necessary.
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  rtl_mirror.Run(&complete_bounds);
2253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Start at full opacity, then loop back and forth five times before ending
2273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // at zero opacity.
2283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->DrawImageInt(*complete, complete_bounds.x(), complete_bounds.y(),
2293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       GetOpacity(animation_progress));
2303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
2313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// static
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid DownloadShelf::PaintDownloadInterrupted(
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gfx::Canvas* canvas,
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const BoundsAdjusterCallback& rtl_mirror,
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int origin_x,
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int origin_y,
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    double animation_progress,
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PaintDownloadProgressSize size) {
2403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Load up our common images.
2413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (!g_foreground_16) {
2423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
2433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_foreground_16 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16);
2443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    g_foreground_32 = rb.GetImageSkiaNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32);
2453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
2463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::ImageSkia* complete = (size == BIG) ? g_foreground_32 : g_foreground_16;
2483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  gfx::Rect complete_bounds(origin_x, origin_y,
2503240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                            complete->width(), complete->height());
2513240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Mirror the positions if necessary.
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  rtl_mirror.Run(&complete_bounds);
2533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
2543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Start at zero opacity, then loop back and forth five times before ending
2553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // at full opacity.
2563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  canvas->DrawImageInt(*complete, complete_bounds.x(), complete_bounds.y(),
2573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                       GetOpacity(1.0 - animation_progress));
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadShelf::AddDownload(DownloadItem* download) {
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(download);
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete()) {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we are going to remove the download from the shelf upon completion,
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // wait a few seconds to see if it completes quickly. If it's a small
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // download, then the user won't have time to interact with it.
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DownloadShelf::ShowDownloadById,
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   download->GetId()),
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetTransientDownloadShowDelay());
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ShowDownload(download);
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadShelf::Show() {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_hidden_) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_show_on_unhide_ = true;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoShow();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DownloadShelf::Close(CloseReason reason) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_hidden_) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_show_on_unhide_ = false;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DoClose(reason);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadShelf::Hide() {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_hidden_)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_hidden_ = true;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsShowing()) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_show_on_unhide_ = true;
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DoClose(AUTOMATIC);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadShelf::Unhide() {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_hidden_)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_hidden_ = false;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (should_show_on_unhide_) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_show_on_unhide_ = false;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoShow();
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::TimeDelta DownloadShelf::GetTransientDownloadShowDelay() {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::TimeDelta::FromSeconds(kDownloadShowDelayInSeconds);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)content::DownloadManager* DownloadShelf::GetDownloadManager() {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return content::BrowserContext::GetDownloadManager(browser()->profile());
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadShelf::ShowDownload(DownloadItem* download) {
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (download->GetState() == DownloadItem::COMPLETE &&
323a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete())
324a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
325a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!DownloadServiceFactory::GetForBrowserContext(
326a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        download->GetBrowserContext())->IsShelfEnabled())
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_hidden_)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Unhide();
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Show();
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoAddDownload(download);
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // browser() can be NULL for tests.
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!browser())
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Show the download started animation if:
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - Download started animation is enabled for this download. It is disabled
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   for "Save As" downloads and extension installs, for example.
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - The browser has an active visible WebContents. (browser isn't minimized,
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   or running under a test etc.)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - Rich animations are enabled.
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebContents* shelf_tab =
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser()->tab_strip_model()->GetActiveWebContents();
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (DownloadItemModel(download).ShouldShowDownloadStartedAnimation() &&
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shelf_tab &&
348010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      platform_util::IsVisible(shelf_tab->GetNativeView()) &&
349d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      gfx::Animation::ShouldRenderRichAnimation()) {
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DownloadStartedAnimation::Show(shelf_tab);
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadShelf::ShowDownloadById(int32 download_id) {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::DownloadManager* download_manager = GetDownloadManager();
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!download_manager)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DownloadItem* download = download_manager->GetDownload(download_id);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!download)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ShowDownload(download);
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
365