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