Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / download / download_status_updater.cc
blob8ea221d1f9e5955104421a6d092bd42524cf30f2
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 #include "chrome/browser/download/download_status_updater.h"
7 #include <vector>
9 #include "base/logging.h"
10 #include "base/stl_util.h"
12 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
13 #include "ui/views/linux_ui/linux_ui.h"
14 #endif
16 namespace {
18 // DownloadStatusUpdater::UpdateAppIconDownloadProgress() expects to only be
19 // called once when a DownloadItem completes, then not again (except perhaps
20 // until it is resumed). The existence of WasInProgressData is effectively a
21 // boolean that indicates whether that final UpdateAppIconDownloadProgress()
22 // call has been made for a given DownloadItem. It is expected that there will
23 // be many more non-in-progress downloads than in-progress downloads, so
24 // WasInProgressData is set for in-progress downloads and cleared from
25 // non-in-progress downloads instead of the other way around in order to save
26 // memory.
27 class WasInProgressData : public base::SupportsUserData::Data {
28 public:
29 static bool Get(content::DownloadItem* item) {
30 return item->GetUserData(kKey) != NULL;
33 static void Clear(content::DownloadItem* item) {
34 item->RemoveUserData(kKey);
37 explicit WasInProgressData(content::DownloadItem* item) {
38 item->SetUserData(kKey, this);
41 private:
42 static const char kKey[];
43 DISALLOW_COPY_AND_ASSIGN(WasInProgressData);
46 const char WasInProgressData::kKey[] =
47 "DownloadItem DownloadStatusUpdater WasInProgressData";
49 } // anonymous namespace
51 DownloadStatusUpdater::DownloadStatusUpdater() {
54 DownloadStatusUpdater::~DownloadStatusUpdater() {
55 STLDeleteElements(&notifiers_);
58 bool DownloadStatusUpdater::GetProgress(float* progress,
59 int* download_count) const {
60 *progress = 0;
61 *download_count = 0;
62 bool progress_certain = true;
63 int64 received_bytes = 0;
64 int64 total_bytes = 0;
66 for (std::vector<AllDownloadItemNotifier*>::const_iterator it =
67 notifiers_.begin(); it != notifiers_.end(); ++it) {
68 if ((*it)->GetManager()) {
69 content::DownloadManager::DownloadVector items;
70 (*it)->GetManager()->GetAllDownloads(&items);
71 for (content::DownloadManager::DownloadVector::const_iterator it =
72 items.begin(); it != items.end(); ++it) {
73 if ((*it)->GetState() == content::DownloadItem::IN_PROGRESS) {
74 ++*download_count;
75 if ((*it)->GetTotalBytes() <= 0) {
76 // There may or may not be more data coming down this pipe.
77 progress_certain = false;
78 } else {
79 received_bytes += (*it)->GetReceivedBytes();
80 total_bytes += (*it)->GetTotalBytes();
87 if (total_bytes > 0)
88 *progress = static_cast<float>(received_bytes) / total_bytes;
89 return progress_certain;
92 void DownloadStatusUpdater::AddManager(content::DownloadManager* manager) {
93 notifiers_.push_back(new AllDownloadItemNotifier(manager, this));
94 content::DownloadManager::DownloadVector items;
95 manager->GetAllDownloads(&items);
96 for (content::DownloadManager::DownloadVector::const_iterator
97 it = items.begin(); it != items.end(); ++it) {
98 OnDownloadCreated(manager, *it);
102 void DownloadStatusUpdater::OnDownloadCreated(
103 content::DownloadManager* manager, content::DownloadItem* item) {
104 // Ignore downloads loaded from history, which are in a terminal state.
105 // TODO(benjhayden): Use the Observer interface to distinguish between
106 // historical and started downloads.
107 if (item->GetState() == content::DownloadItem::IN_PROGRESS) {
108 UpdateAppIconDownloadProgress(item);
109 new WasInProgressData(item);
111 // else, the lack of WasInProgressData indicates to OnDownloadUpdated that it
112 // should not call UpdateAppIconDownloadProgress().
115 void DownloadStatusUpdater::OnDownloadUpdated(
116 content::DownloadManager* manager, content::DownloadItem* item) {
117 if (item->GetState() == content::DownloadItem::IN_PROGRESS) {
118 // If the item was interrupted/cancelled and then resumed/restarted, then
119 // set WasInProgress so that UpdateAppIconDownloadProgress() will be called
120 // when it completes.
121 if (!WasInProgressData::Get(item))
122 new WasInProgressData(item);
123 } else {
124 // The item is now in a terminal state. If it was already in a terminal
125 // state, then do not call UpdateAppIconDownloadProgress() again. If it is
126 // now transitioning to a terminal state, then clear its WasInProgressData
127 // so that UpdateAppIconDownloadProgress() won't be called after this final
128 // call.
129 if (!WasInProgressData::Get(item))
130 return;
131 WasInProgressData::Clear(item);
133 UpdateAppIconDownloadProgress(item);
136 #if defined(OS_ANDROID) || (defined(USE_AURA) && !defined(OS_WIN))
137 void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
138 content::DownloadItem* download) {
139 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
140 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
141 if (linux_ui) {
142 float progress = 0;
143 int download_count = 0;
144 GetProgress(&progress, &download_count);
145 linux_ui->SetDownloadCount(download_count);
146 linux_ui->SetProgressFraction(progress);
148 #endif
149 // TODO(avi): Implement for Android?
151 #endif