• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/download/download_status_updater.h"
6 
7 #include <vector>
8 
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 
12 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
13 #include "ui/views/linux_ui/linux_ui.h"
14 #endif
15 
16 namespace {
17 
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:
Get(content::DownloadItem * item)29   static bool Get(content::DownloadItem* item) {
30     return item->GetUserData(kKey) != NULL;
31   }
32 
Clear(content::DownloadItem * item)33   static void Clear(content::DownloadItem* item) {
34     item->RemoveUserData(kKey);
35   }
36 
WasInProgressData(content::DownloadItem * item)37   explicit WasInProgressData(content::DownloadItem* item) {
38     item->SetUserData(kKey, this);
39   }
40 
41  private:
42   static const char kKey[];
43   DISALLOW_COPY_AND_ASSIGN(WasInProgressData);
44 };
45 
46 const char WasInProgressData::kKey[] =
47   "DownloadItem DownloadStatusUpdater WasInProgressData";
48 
49 }  // anonymous namespace
50 
DownloadStatusUpdater()51 DownloadStatusUpdater::DownloadStatusUpdater() {
52 }
53 
~DownloadStatusUpdater()54 DownloadStatusUpdater::~DownloadStatusUpdater() {
55   STLDeleteElements(&notifiers_);
56 }
57 
GetProgress(float * progress,int * download_count) const58 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;
65 
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();
81           }
82         }
83       }
84     }
85   }
86 
87   if (total_bytes > 0)
88     *progress = static_cast<float>(received_bytes) / total_bytes;
89   return progress_certain;
90 }
91 
AddManager(content::DownloadManager * manager)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);
99   }
100 }
101 
OnDownloadCreated(content::DownloadManager * manager,content::DownloadItem * item)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);
110   }
111   // else, the lack of WasInProgressData indicates to OnDownloadUpdated that it
112   // should not call UpdateAppIconDownloadProgress().
113 }
114 
OnDownloadUpdated(content::DownloadManager * manager,content::DownloadItem * item)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);
132   }
133   UpdateAppIconDownloadProgress(item);
134 }
135 
136 #if defined(OS_ANDROID) || (defined(USE_AURA) && !defined(OS_WIN))
UpdateAppIconDownloadProgress(content::DownloadItem * download)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);
147   }
148 #endif
149   // TODO(avi): Implement for Android?
150 }
151 #endif
152