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"
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"
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
27 class WasInProgressData
: public base::SupportsUserData::Data
{
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);
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(¬ifiers_
);
58 bool DownloadStatusUpdater::GetProgress(float* progress
,
59 int* download_count
) const {
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
) {
75 if ((*it
)->GetTotalBytes() <= 0) {
76 // There may or may not be more data coming down this pipe.
77 progress_certain
= false;
79 received_bytes
+= (*it
)->GetReceivedBytes();
80 total_bytes
+= (*it
)->GetTotalBytes();
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
);
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
129 if (!WasInProgressData::Get(item
))
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();
143 int download_count
= 0;
144 GetProgress(&progress
, &download_count
);
145 linux_ui
->SetDownloadCount(download_count
);
146 linux_ui
->SetProgressFraction(progress
);
149 // TODO(avi): Implement for Android?