• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/ui/webui/active_downloads_ui.h"
6 
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10 
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/logging.h"
15 #include "base/memory/singleton.h"
16 #include "base/message_loop.h"
17 #include "base/path_service.h"
18 #include "base/string_piece.h"
19 #include "base/string_util.h"
20 #include "base/threading/thread.h"
21 #include "base/time.h"
22 #include "base/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "chrome/browser/chromeos/cros/cros_library.h"
25 #include "chrome/browser/chromeos/login/user_manager.h"
26 #include "chrome/browser/download/download_item.h"
27 #include "chrome/browser/download/download_manager.h"
28 #include "chrome/browser/download/download_util.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/tabs/tab_strip_model.h"
31 #include "chrome/browser/ui/browser.h"
32 #include "chrome/browser/ui/browser_list.h"
33 #include "chrome/browser/ui/browser_window.h"
34 #include "chrome/browser/ui/webui/favicon_source.h"
35 #include "chrome/browser/ui/webui/mediaplayer_ui.h"
36 #include "chrome/common/chrome_paths.h"
37 #include "chrome/common/chrome_switches.h"
38 #include "chrome/common/jstemplate_builder.h"
39 #include "chrome/common/net/url_fetcher.h"
40 #include "chrome/common/url_constants.h"
41 #include "content/browser/browser_thread.h"
42 #include "content/browser/tab_contents/tab_contents.h"
43 #include "grit/browser_resources.h"
44 #include "grit/chromium_strings.h"
45 #include "grit/generated_resources.h"
46 #include "grit/locale_settings.h"
47 #include "net/base/escape.h"
48 #include "net/url_request/url_request_file_job.h"
49 #include "ui/base/l10n/l10n_util.h"
50 #include "ui/base/resource/resource_bundle.h"
51 
52 namespace {
53 
54 static const int kPopupLeft = 0;
55 static const int kPopupTop = 0;
56 static const int kPopupWidth = 250;
57 // Minimum height of window must be 100, so kPopupHeight has space for
58 // 2 download rows of 36 px and 'Show All Downloads' which is 29px.
59 static const int kPopupHeight = 36 * 2 + 29;
60 
61 static const char kPropertyPath[] = "path";
62 static const char kPropertyTitle[] = "title";
63 static const char kPropertyDirectory[] = "isDirectory";
64 
65 class ActiveDownloadsUIHTMLSource : public ChromeURLDataManager::DataSource {
66  public:
67   ActiveDownloadsUIHTMLSource();
68 
69   // Called when the network layer has requested a resource underneath
70   // the path we registered.
71   virtual void StartDataRequest(const std::string& path,
72                                 bool is_incognito,
73                                 int request_id);
GetMimeType(const std::string &) const74   virtual std::string GetMimeType(const std::string&) const {
75     return "text/html";
76   }
77 
78  private:
~ActiveDownloadsUIHTMLSource()79   ~ActiveDownloadsUIHTMLSource() {}
80 
81   DISALLOW_COPY_AND_ASSIGN(ActiveDownloadsUIHTMLSource);
82 };
83 
84 // The handler for Javascript messages related to the "active_downloads" view.
85 class ActiveDownloadsHandler
86     : public WebUIMessageHandler,
87       public DownloadManager::Observer,
88       public DownloadItem::Observer {
89  public:
90   ActiveDownloadsHandler();
91   virtual ~ActiveDownloadsHandler();
92 
93   // Initialization after Attach.
94   void Init();
95 
96   // WebUIMessageHandler implementation.
97   virtual WebUIMessageHandler* Attach(WebUI* web_ui);
98   virtual void RegisterMessages();
99 
100   // DownloadItem::Observer interface.
101   virtual void OnDownloadUpdated(DownloadItem* item);
OnDownloadOpened(DownloadItem * item)102   virtual void OnDownloadOpened(DownloadItem* item) { }
103 
104   // DownloadManager::Observer interface.
105   virtual void ModelChanged();
106 
107   // WebUI Callbacks.
108   void HandleGetDownloads(const ListValue* args);
109   void HandlePauseToggleDownload(const ListValue* args);
110   void HandleCancelDownload(const ListValue* args);
111   void HandleAllowDownload(const ListValue* args);
112   void OpenNewPopupWindow(const ListValue* args);
113   void OpenNewFullWindow(const ListValue* args);
114   void PlayMediaFile(const ListValue* args);
115 
116  private:
117   // Downloads helpers.
118   DownloadItem* GetDownloadById(const ListValue* args);
119   void UpdateDownloadList();
120   void SendDownloads();
121   void AddDownload(DownloadItem* item);
122 
123   void OpenNewWindow(const ListValue* args, bool popup);
124 
125   Profile* profile_;
126   TabContents* tab_contents_;
127   DownloadManager* download_manager_;
128 
129   typedef std::vector<DownloadItem*> DownloadList;
130   DownloadList active_downloads_;
131   DownloadList downloads_;
132 
133   DISALLOW_COPY_AND_ASSIGN(ActiveDownloadsHandler);
134 };
135 
136 ////////////////////////////////////////////////////////////////////////////////
137 //
138 // ActiveDownloadsUIHTMLSource
139 //
140 ////////////////////////////////////////////////////////////////////////////////
141 
ActiveDownloadsUIHTMLSource()142 ActiveDownloadsUIHTMLSource::ActiveDownloadsUIHTMLSource()
143     : DataSource(chrome::kChromeUIActiveDownloadsHost, MessageLoop::current()) {
144 }
145 
StartDataRequest(const std::string & path,bool is_incognito,int request_id)146 void ActiveDownloadsUIHTMLSource::StartDataRequest(const std::string& path,
147                                               bool is_incognito,
148                                               int request_id) {
149   DictionaryValue localized_strings;
150   localized_strings.SetString("allowdownload",
151       l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DOWNLOAD));
152   localized_strings.SetString("cancel",
153       l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_CANCEL));
154   localized_strings.SetString("confirmcancel",
155       l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_CANCEL));
156   localized_strings.SetString("confirmyes",
157       l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_YES));
158   localized_strings.SetString("open",
159       l10n_util::GetStringUTF16(IDS_FILEBROWSER_OPEN));
160   localized_strings.SetString("pause",
161       l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_PAUSE));
162   localized_strings.SetString("resume",
163       l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_RESUME));
164   localized_strings.SetString("showalldownloads",
165       l10n_util::GetStringUTF16(IDS_FILEBROWSER_SHOW_ALL_DOWNLOADS));
166   FilePath default_download_path;
167   if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
168                         &default_download_path)) {
169     NOTREACHED();
170   }
171   // TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode.
172   localized_strings.SetString("downloadpath", default_download_path.value());
173   localized_strings.SetString("error_unknown_file_type",
174       l10n_util::GetStringUTF16(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE));
175   SetFontAndTextDirection(&localized_strings);
176 
177   static const base::StringPiece active_downloads_html(
178       ResourceBundle::GetSharedInstance().GetRawDataResource(
179           IDR_ACTIVE_DOWNLOADS_HTML));
180   const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
181       active_downloads_html, &localized_strings);
182 
183   scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
184   html_bytes->data.resize(full_html.size());
185   std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
186 
187   SendResponse(request_id, html_bytes);
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 //
192 // ActiveDownloadsHandler
193 //
194 ////////////////////////////////////////////////////////////////////////////////
195 
ActiveDownloadsHandler()196 ActiveDownloadsHandler::ActiveDownloadsHandler()
197     : profile_(NULL),
198       tab_contents_(NULL),
199       download_manager_(NULL) {
200 }
201 
~ActiveDownloadsHandler()202 ActiveDownloadsHandler::~ActiveDownloadsHandler() {
203   for (size_t i = 0; i < downloads_.size(); ++i) {
204     downloads_[i]->RemoveObserver(this);
205   }
206   download_manager_->RemoveObserver(this);
207 }
208 
Attach(WebUI * web_ui)209 WebUIMessageHandler* ActiveDownloadsHandler::Attach(WebUI* web_ui) {
210   // Create our favicon data source.
211   profile_ = web_ui->GetProfile();
212   profile_->GetChromeURLDataManager()->AddDataSource(
213       new FaviconSource(profile_));
214   tab_contents_ = web_ui->tab_contents();
215   return WebUIMessageHandler::Attach(web_ui);
216 }
217 
Init()218 void ActiveDownloadsHandler::Init() {
219   download_manager_ = profile_->GetDownloadManager();
220   download_manager_->AddObserver(this);
221 }
222 
RegisterMessages()223 void ActiveDownloadsHandler::RegisterMessages() {
224   web_ui_->RegisterMessageCallback("getDownloads",
225       NewCallback(this, &ActiveDownloadsHandler::HandleGetDownloads));
226   web_ui_->RegisterMessageCallback("pauseToggleDownload",
227       NewCallback(this, &ActiveDownloadsHandler::HandlePauseToggleDownload));
228   web_ui_->RegisterMessageCallback("cancelDownload",
229       NewCallback(this, &ActiveDownloadsHandler::HandleCancelDownload));
230   web_ui_->RegisterMessageCallback("allowDownload",
231       NewCallback(this, &ActiveDownloadsHandler::HandleAllowDownload));
232   web_ui_->RegisterMessageCallback("openNewPopupWindow",
233       NewCallback(this, &ActiveDownloadsHandler::OpenNewPopupWindow));
234   web_ui_->RegisterMessageCallback("openNewFullWindow",
235       NewCallback(this, &ActiveDownloadsHandler::OpenNewFullWindow));
236   web_ui_->RegisterMessageCallback("playMediaFile",
237       NewCallback(this, &ActiveDownloadsHandler::PlayMediaFile));
238 }
239 
PlayMediaFile(const ListValue * args)240 void ActiveDownloadsHandler::PlayMediaFile(const ListValue* args) {
241   FilePath file_path(UTF16ToUTF8(ExtractStringValue(args)));
242 
243   Browser* browser = Browser::GetBrowserForController(
244       &tab_contents_->controller(), NULL);
245   MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
246   mediaplayer->ForcePlayMediaFile(profile_, file_path, browser);
247 }
248 
GetDownloadById(const ListValue * args)249 DownloadItem* ActiveDownloadsHandler::GetDownloadById(
250     const ListValue* args) {
251   int i;
252   if (!ExtractIntegerValue(args, &i))
253     return NULL;
254   size_t id(i);
255   return id < downloads_.size() ? downloads_[id] : NULL;
256 }
257 
HandlePauseToggleDownload(const ListValue * args)258 void ActiveDownloadsHandler::HandlePauseToggleDownload(const ListValue* args) {
259   DownloadItem* item = GetDownloadById(args);
260   if (item && item->IsPartialDownload())
261     item->TogglePause();
262 }
263 
HandleAllowDownload(const ListValue * args)264 void ActiveDownloadsHandler::HandleAllowDownload(const ListValue* args) {
265   DownloadItem* item = GetDownloadById(args);
266   if (item)
267     item->DangerousDownloadValidated();
268 }
269 
HandleCancelDownload(const ListValue * args)270 void ActiveDownloadsHandler::HandleCancelDownload(const ListValue* args) {
271   DownloadItem* item = GetDownloadById(args);
272   if (item) {
273     if (item->IsPartialDownload())
274       item->Cancel(true);
275     item->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
276   }
277 }
278 
OpenNewFullWindow(const ListValue * args)279 void ActiveDownloadsHandler::OpenNewFullWindow(const ListValue* args) {
280   OpenNewWindow(args, false);
281 }
282 
OpenNewPopupWindow(const ListValue * args)283 void ActiveDownloadsHandler::OpenNewPopupWindow(const ListValue* args) {
284   OpenNewWindow(args, true);
285 }
286 
OpenNewWindow(const ListValue * args,bool popup)287 void ActiveDownloadsHandler::OpenNewWindow(const ListValue* args, bool popup) {
288   std::string url = UTF16ToUTF8(ExtractStringValue(args));
289   Browser* browser = popup ?
290       Browser::CreateForType(Browser::TYPE_APP_PANEL, profile_) :
291       BrowserList::GetLastActive();
292   browser::NavigateParams params(browser, GURL(url), PageTransition::LINK);
293   params.disposition = NEW_FOREGROUND_TAB;
294   browser::Navigate(&params);
295   // TODO(beng): The following two calls should be automatic by Navigate().
296   if (popup)
297     params.browser->window()->SetBounds(gfx::Rect(0, 0, 400, 300));
298   params.browser->window()->Show();
299 }
300 
ModelChanged()301 void ActiveDownloadsHandler::ModelChanged() {
302   UpdateDownloadList();
303 }
304 
HandleGetDownloads(const ListValue * args)305 void ActiveDownloadsHandler::HandleGetDownloads(const ListValue* args) {
306   UpdateDownloadList();
307 }
308 
UpdateDownloadList()309 void ActiveDownloadsHandler::UpdateDownloadList() {
310   DownloadList downloads;
311   download_manager_->GetAllDownloads(FilePath(), &downloads);
312   active_downloads_.clear();
313   for (size_t i = 0; i < downloads.size(); ++i) {
314     AddDownload(downloads[i]);
315   }
316   SendDownloads();
317 }
318 
AddDownload(DownloadItem * item)319 void ActiveDownloadsHandler::AddDownload(DownloadItem* item) {
320   // Observe in progress and dangerous downloads.
321   if (item->state() == DownloadItem::IN_PROGRESS ||
322       item->safety_state() == DownloadItem::DANGEROUS) {
323     active_downloads_.push_back(item);
324 
325     DownloadList::const_iterator it =
326       std::find(downloads_.begin(), downloads_.end(), item);
327     if (it == downloads_.end()) {
328       downloads_.push_back(item);
329       item->AddObserver(this);
330     }
331   }
332 }
333 
SendDownloads()334 void ActiveDownloadsHandler::SendDownloads() {
335   ListValue results;
336   for (size_t i = 0; i < downloads_.size(); ++i) {
337     results.Append(download_util::CreateDownloadItemValue(downloads_[i], i));
338   }
339 
340   web_ui_->CallJavascriptFunction("downloadsList", results);
341 }
342 
OnDownloadUpdated(DownloadItem * item)343 void ActiveDownloadsHandler::OnDownloadUpdated(DownloadItem* item) {
344   DownloadList::iterator it =
345       find(downloads_.begin(), downloads_.end(), item);
346 
347   if (it == downloads_.end()) {
348     NOTREACHED() << "Updated item " << item->full_path().value()
349       << " not found";
350   }
351 
352   if (item->state() == DownloadItem::REMOVING) {
353     item->RemoveObserver(this);
354     downloads_.erase(it);
355     DownloadList::iterator ita =
356         find(active_downloads_.begin(), active_downloads_.end(), item);
357     if (ita != active_downloads_.end())
358       active_downloads_.erase(ita);
359     SendDownloads();
360   } else {
361     const size_t id = it - downloads_.begin();
362     scoped_ptr<DictionaryValue> result(
363         download_util::CreateDownloadItemValue(item, id));
364     web_ui_->CallJavascriptFunction("downloadUpdated", *result);
365   }
366 }
367 
368 }  // namespace
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 //
372 // ActiveDownloadsUI
373 //
374 ////////////////////////////////////////////////////////////////////////////////
375 
376 
ActiveDownloadsUI(TabContents * contents)377 ActiveDownloadsUI::ActiveDownloadsUI(TabContents* contents)
378     : HtmlDialogUI(contents) {
379   ActiveDownloadsHandler* handler = new ActiveDownloadsHandler();
380   AddMessageHandler(handler->Attach(this));
381   handler->Init();
382   ActiveDownloadsUIHTMLSource* html_source = new ActiveDownloadsUIHTMLSource();
383 
384   // Set up the chrome://active-downloads/ source.
385   contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
386 }
387 
388 // static
OpenPopup(Profile * profile)389 Browser* ActiveDownloadsUI::OpenPopup(Profile* profile) {
390   Browser* browser = GetPopup(profile);
391 
392   // Create new browser if no matching pop up is found.
393   if (browser == NULL) {
394     browser = Browser::CreateForType(Browser::TYPE_APP_PANEL, profile);
395 
396     browser::NavigateParams params(
397         browser,
398         GURL(chrome::kChromeUIActiveDownloadsURL),
399         PageTransition::LINK);
400     params.disposition = NEW_FOREGROUND_TAB;
401     browser::Navigate(&params);
402 
403     // TODO(beng): The following two calls should be automatic by Navigate().
404     params.browser->window()->SetBounds(gfx::Rect(kPopupLeft,
405                                                   kPopupTop,
406                                                   kPopupWidth,
407                                                   kPopupHeight));
408     params.browser->window()->Show();
409   } else {
410     browser->window()->Show();
411   }
412 
413   return browser;
414 }
415 
GetPopup(Profile * profile)416 Browser* ActiveDownloadsUI::GetPopup(Profile* profile) {
417   for (BrowserList::const_iterator it = BrowserList::begin();
418        it != BrowserList::end();
419        ++it) {
420     if (((*it)->type() == Browser::TYPE_APP_PANEL)) {
421       TabContents* tab_contents = (*it)->GetSelectedTabContents();
422       DCHECK(tab_contents);
423       if (!tab_contents)
424         continue;
425       const GURL& url = tab_contents->GetURL();
426 
427       if (url.SchemeIs(chrome::kChromeUIScheme) &&
428           url.host() == chrome::kChromeUIActiveDownloadsHost &&
429           (*it)->profile() == profile) {
430         return (*it);
431       }
432     }
433   }
434   return NULL;
435 }
436 
437