Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / downloads_dom_handler.cc
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/ui/webui/downloads_dom_handler.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/i18n/rtl.h"
14 #include "base/i18n/time_formatting.h"
15 #include "base/memory/singleton.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/histogram.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/thread.h"
22 #include "base/value_conversions.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/download/download_crx_util.h"
26 #include "chrome/browser/download/download_danger_prompt.h"
27 #include "chrome/browser/download/download_history.h"
28 #include "chrome/browser/download/download_item_model.h"
29 #include "chrome/browser/download/download_prefs.h"
30 #include "chrome/browser/download/download_query.h"
31 #include "chrome/browser/download/download_service.h"
32 #include "chrome/browser/download/download_service_factory.h"
33 #include "chrome/browser/download/drag_download_item.h"
34 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
35 #include "chrome/browser/extensions/extension_service.h"
36 #include "chrome/browser/platform_util.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/ui/webui/fileicon_source.h"
39 #include "chrome/common/pref_names.h"
40 #include "chrome/common/url_constants.h"
41 #include "content/public/browser/browser_thread.h"
42 #include "content/public/browser/download_item.h"
43 #include "content/public/browser/url_data_source.h"
44 #include "content/public/browser/user_metrics.h"
45 #include "content/public/browser/web_contents.h"
46 #include "content/public/browser/web_ui.h"
47 #include "extensions/browser/extension_system.h"
48 #include "grit/generated_resources.h"
49 #include "net/base/filename_util.h"
50 #include "ui/base/l10n/time_format.h"
51 #include "ui/gfx/image/image.h"
52
53 using base::UserMetricsAction;
54 using content::BrowserContext;
55 using content::BrowserThread;
56
57 namespace {
58
59 // Maximum number of downloads to show. TODO(glen): Remove this and instead
60 // stuff the downloads down the pipe slowly.
61 static const size_t kMaxDownloads = 150;
62
63 enum DownloadsDOMEvent {
64   DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
65   DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
66   DOWNLOADS_DOM_EVENT_DRAG = 2,
67   DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3,
68   DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4,
69   DOWNLOADS_DOM_EVENT_SHOW = 5,
70   DOWNLOADS_DOM_EVENT_PAUSE = 6,
71   DOWNLOADS_DOM_EVENT_REMOVE = 7,
72   DOWNLOADS_DOM_EVENT_CANCEL = 8,
73   DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9,
74   DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10,
75   DOWNLOADS_DOM_EVENT_RESUME = 11,
76   DOWNLOADS_DOM_EVENT_MAX
77 };
78
79 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
80   UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
81                             event,
82                             DOWNLOADS_DOM_EVENT_MAX);
83 }
84
85 // Returns a string constant to be used as the |danger_type| value in
86 // CreateDownloadItemValue().  Only return strings for DANGEROUS_FILE,
87 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
88 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
89 const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
90   switch (danger_type) {
91     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
92       return "DANGEROUS_FILE";
93     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
94       return "DANGEROUS_URL";
95     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
96       return "DANGEROUS_CONTENT";
97     case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
98       return "UNCOMMON_CONTENT";
99     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
100       return "DANGEROUS_HOST";
101     case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
102       return "POTENTIALLY_UNWANTED";
103     default:
104       // Don't return a danger type string if it is NOT_DANGEROUS or
105       // MAYBE_DANGEROUS_CONTENT.
106       NOTREACHED();
107       return "";
108   }
109 }
110
111 // Returns a JSON dictionary containing some of the attributes of |download|.
112 // The JSON dictionary will also have a field "id" set to |id|, and a field
113 // "otr" set to |incognito|.
114 base::DictionaryValue* CreateDownloadItemValue(
115     content::DownloadItem* download_item,
116     bool incognito) {
117   // TODO(asanka): Move towards using download_model here for getting status and
118   // progress. The difference currently only matters to Drive downloads and
119   // those don't show up on the downloads page, but should.
120   DownloadItemModel download_model(download_item);
121   base::DictionaryValue* file_value = new base::DictionaryValue();
122
123   file_value->SetInteger(
124       "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
125   file_value->SetString(
126       "since_string", ui::TimeFormat::RelativeDate(
127           download_item->GetStartTime(), NULL));
128   file_value->SetString(
129       "date_string", base::TimeFormatShortDate(download_item->GetStartTime()));
130   file_value->SetInteger("id", download_item->GetId());
131
132   base::FilePath download_path(download_item->GetTargetFilePath());
133   file_value->Set("file_path", base::CreateFilePathValue(download_path));
134   file_value->SetString("file_url",
135                         net::FilePathToFileURL(download_path).spec());
136
137   extensions::DownloadedByExtension* by_ext =
138       extensions::DownloadedByExtension::Get(download_item);
139   if (by_ext) {
140     file_value->SetString("by_ext_id", by_ext->id());
141     file_value->SetString("by_ext_name", by_ext->name());
142     // Lookup the extension's current name() in case the user changed their
143     // language. This won't work if the extension was uninstalled, so the name
144     // might be the wrong language.
145     bool include_disabled = true;
146     const extensions::Extension* extension = extensions::ExtensionSystem::Get(
147         Profile::FromBrowserContext(download_item->GetBrowserContext()))->
148       extension_service()->GetExtensionById(by_ext->id(), include_disabled);
149     if (extension)
150       file_value->SetString("by_ext_name", extension->name());
151   }
152
153   // Keep file names as LTR.
154   base::string16 file_name =
155     download_item->GetFileNameToReportUser().LossyDisplayName();
156   file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
157   file_value->SetString("file_name", file_name);
158   file_value->SetString("url", download_item->GetURL().spec());
159   file_value->SetBoolean("otr", incognito);
160   file_value->SetInteger("total", static_cast<int>(
161       download_item->GetTotalBytes()));
162   file_value->SetBoolean("file_externally_removed",
163                          download_item->GetFileExternallyRemoved());
164   file_value->SetBoolean("retry", false); // Overridden below if needed.
165   file_value->SetBoolean("resume", download_item->CanResume());
166
167   switch (download_item->GetState()) {
168     case content::DownloadItem::IN_PROGRESS:
169       if (download_item->IsDangerous()) {
170         file_value->SetString("state", "DANGEROUS");
171         // These are the only danger states that the UI is equipped to handle.
172         DCHECK(download_item->GetDangerType() ==
173                    content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
174                download_item->GetDangerType() ==
175                    content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
176                download_item->GetDangerType() ==
177                    content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
178                download_item->GetDangerType() ==
179                    content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
180                download_item->GetDangerType() ==
181                    content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
182                download_item->GetDangerType() ==
183                    content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
184         const char* danger_type_value =
185             GetDangerTypeString(download_item->GetDangerType());
186         file_value->SetString("danger_type", danger_type_value);
187       } else if (download_item->IsPaused()) {
188         file_value->SetString("state", "PAUSED");
189       } else {
190         file_value->SetString("state", "IN_PROGRESS");
191       }
192       file_value->SetString("progress_status_text",
193                             download_model.GetTabProgressStatusText());
194
195       file_value->SetInteger("percent",
196           static_cast<int>(download_item->PercentComplete()));
197       file_value->SetInteger("received",
198           static_cast<int>(download_item->GetReceivedBytes()));
199       break;
200
201     case content::DownloadItem::INTERRUPTED:
202       file_value->SetString("state", "INTERRUPTED");
203
204       file_value->SetString("progress_status_text",
205                             download_model.GetTabProgressStatusText());
206
207       file_value->SetInteger("percent",
208           static_cast<int>(download_item->PercentComplete()));
209       file_value->SetInteger("received",
210           static_cast<int>(download_item->GetReceivedBytes()));
211       file_value->SetString("last_reason_text",
212                             download_model.GetInterruptReasonText());
213       if (content::DOWNLOAD_INTERRUPT_REASON_CRASH ==
214           download_item->GetLastReason() && !download_item->CanResume())
215         file_value->SetBoolean("retry", true);
216       break;
217
218     case content::DownloadItem::CANCELLED:
219       file_value->SetString("state", "CANCELLED");
220       file_value->SetBoolean("retry", true);
221       break;
222
223     case content::DownloadItem::COMPLETE:
224       DCHECK(!download_item->IsDangerous());
225       file_value->SetString("state", "COMPLETE");
226       break;
227
228     case content::DownloadItem::MAX_DOWNLOAD_STATE:
229       NOTREACHED() << "state undefined";
230   }
231
232   return file_value;
233 }
234
235 // Filters out extension downloads and downloads that don't have a filename yet.
236 bool IsDownloadDisplayable(const content::DownloadItem& item) {
237   return (!download_crx_util::IsExtensionDownload(item) &&
238           !item.IsTemporary() &&
239           !item.GetFileNameToReportUser().empty() &&
240           !item.GetTargetFilePath().empty());
241 }
242
243 }  // namespace
244
245 DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm)
246     : main_notifier_(dlm, this),
247       update_scheduled_(false),
248       weak_ptr_factory_(this) {
249   // Create our fileicon data source.
250   Profile* profile = Profile::FromBrowserContext(dlm->GetBrowserContext());
251   content::URLDataSource::Add(profile, new FileIconSource());
252
253   if (profile->IsOffTheRecord()) {
254     original_notifier_.reset(new AllDownloadItemNotifier(
255         BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
256         this));
257   }
258 }
259
260 DownloadsDOMHandler::~DownloadsDOMHandler() {
261 }
262
263 // DownloadsDOMHandler, public: -----------------------------------------------
264
265 void DownloadsDOMHandler::OnPageLoaded(const base::ListValue* args) {
266   SendCurrentDownloads();
267 }
268
269 void DownloadsDOMHandler::RegisterMessages() {
270   web_ui()->RegisterMessageCallback("onPageLoaded",
271       base::Bind(&DownloadsDOMHandler::OnPageLoaded,
272                  weak_ptr_factory_.GetWeakPtr()));
273   web_ui()->RegisterMessageCallback("getDownloads",
274       base::Bind(&DownloadsDOMHandler::HandleGetDownloads,
275                  weak_ptr_factory_.GetWeakPtr()));
276   web_ui()->RegisterMessageCallback("openFile",
277       base::Bind(&DownloadsDOMHandler::HandleOpenFile,
278                  weak_ptr_factory_.GetWeakPtr()));
279   web_ui()->RegisterMessageCallback("drag",
280       base::Bind(&DownloadsDOMHandler::HandleDrag,
281                  weak_ptr_factory_.GetWeakPtr()));
282   web_ui()->RegisterMessageCallback("saveDangerous",
283       base::Bind(&DownloadsDOMHandler::HandleSaveDangerous,
284                  weak_ptr_factory_.GetWeakPtr()));
285   web_ui()->RegisterMessageCallback("discardDangerous",
286       base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous,
287                  weak_ptr_factory_.GetWeakPtr()));
288   web_ui()->RegisterMessageCallback("show",
289       base::Bind(&DownloadsDOMHandler::HandleShow,
290                  weak_ptr_factory_.GetWeakPtr()));
291   web_ui()->RegisterMessageCallback("pause",
292       base::Bind(&DownloadsDOMHandler::HandlePause,
293                  weak_ptr_factory_.GetWeakPtr()));
294   web_ui()->RegisterMessageCallback("resume",
295       base::Bind(&DownloadsDOMHandler::HandleResume,
296                  weak_ptr_factory_.GetWeakPtr()));
297   web_ui()->RegisterMessageCallback("remove",
298       base::Bind(&DownloadsDOMHandler::HandleRemove,
299                  weak_ptr_factory_.GetWeakPtr()));
300   web_ui()->RegisterMessageCallback("cancel",
301       base::Bind(&DownloadsDOMHandler::HandleCancel,
302                  weak_ptr_factory_.GetWeakPtr()));
303   web_ui()->RegisterMessageCallback("clearAll",
304       base::Bind(&DownloadsDOMHandler::HandleClearAll,
305                  weak_ptr_factory_.GetWeakPtr()));
306   web_ui()->RegisterMessageCallback("openDownloadsFolder",
307       base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder,
308                  weak_ptr_factory_.GetWeakPtr()));
309 }
310
311 void DownloadsDOMHandler::OnDownloadCreated(
312     content::DownloadManager* manager, content::DownloadItem* download_item) {
313   if (IsDownloadDisplayable(*download_item))
314     ScheduleSendCurrentDownloads();
315 }
316
317 void DownloadsDOMHandler::OnDownloadUpdated(
318     content::DownloadManager* manager,
319     content::DownloadItem* download_item) {
320   if (IsDownloadDisplayable(*download_item)) {
321     if (search_terms_ && !search_terms_->empty()) {
322       // Don't CallDownloadUpdated() if download_item doesn't match
323       // search_terms_.
324       // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
325       content::DownloadManager::DownloadVector all_items, filtered_items;
326       all_items.push_back(download_item);
327       DownloadQuery query;
328       query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_.get());
329       query.Search(all_items.begin(), all_items.end(), &filtered_items);
330       if (filtered_items.empty())
331         return;
332     }
333     base::ListValue results_value;
334     results_value.Append(CreateDownloadItemValue(
335         download_item,
336         (original_notifier_.get() &&
337           (manager == main_notifier_.GetManager()))));
338     CallDownloadUpdated(results_value);
339   }
340 }
341
342 void DownloadsDOMHandler::OnDownloadRemoved(
343     content::DownloadManager* manager,
344     content::DownloadItem* download_item) {
345   // This relies on |download_item| being removed from DownloadManager in this
346   // MessageLoop iteration. |download_item| may not have been removed from
347   // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
348   // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
349   // at all downloads, and we do not tell it that |download_item| is being
350   // removed. If DownloadManager is ever changed to not immediately remove
351   // |download_item| from its map when OnDownloadRemoved is sent, then
352   // DownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
353   // SendCurrentDownloads() that |download_item| was removed. A
354   // SupportsUserData::Data would be the correct way to do this.
355   ScheduleSendCurrentDownloads();
356 }
357
358 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
359   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
360   search_terms_.reset((args && !args->empty()) ? args->DeepCopy() : NULL);
361   SendCurrentDownloads();
362 }
363
364 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
365   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
366   content::DownloadItem* file = GetDownloadByValue(args);
367   if (file)
368     file->OpenDownload();
369 }
370
371 void DownloadsDOMHandler::HandleDrag(const base::ListValue* args) {
372   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG);
373   content::DownloadItem* file = GetDownloadByValue(args);
374   if (!file)
375     return;
376
377   content::WebContents* web_contents = GetWebUIWebContents();
378   // |web_contents| is only NULL in the test.
379   if (!web_contents)
380     return;
381
382   if (file->GetState() != content::DownloadItem::COMPLETE)
383     return;
384
385   gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
386       file->GetTargetFilePath(), IconLoader::NORMAL);
387   gfx::NativeView view = web_contents->GetNativeView();
388   {
389     // Enable nested tasks during DnD, while |DragDownload()| blocks.
390     base::MessageLoop::ScopedNestableTaskAllower allow(
391         base::MessageLoop::current());
392     DragDownloadItem(file, icon, view);
393   }
394 }
395
396 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue* args) {
397   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
398   content::DownloadItem* file = GetDownloadByValue(args);
399   if (file)
400     ShowDangerPrompt(file);
401 }
402
403 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue* args) {
404   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS);
405   content::DownloadItem* file = GetDownloadByValue(args);
406   if (file)
407     file->Remove();
408 }
409
410 void DownloadsDOMHandler::HandleShow(const base::ListValue* args) {
411   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW);
412   content::DownloadItem* file = GetDownloadByValue(args);
413   if (file)
414     file->ShowDownloadInShell();
415 }
416
417 void DownloadsDOMHandler::HandlePause(const base::ListValue* args) {
418   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE);
419   content::DownloadItem* file = GetDownloadByValue(args);
420   if (file)
421     file->Pause();
422 }
423
424 void DownloadsDOMHandler::HandleResume(const base::ListValue* args) {
425   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME);
426   content::DownloadItem* file = GetDownloadByValue(args);
427   if (file)
428     file->Resume();
429 }
430
431 void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) {
432   if (!IsDeletingHistoryAllowed())
433     return;
434
435   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE);
436   content::DownloadItem* file = GetDownloadByValue(args);
437   if (file)
438     file->Remove();
439 }
440
441 void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) {
442   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL);
443   content::DownloadItem* file = GetDownloadByValue(args);
444   if (file)
445     file->Cancel(true);
446 }
447
448 void DownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
449   if (IsDeletingHistoryAllowed()) {
450     CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
451     // IsDeletingHistoryAllowed already checked for the existence of the
452     // manager.
453     main_notifier_.GetManager()->RemoveAllDownloads();
454
455     // If this is an incognito downloads page, clear All should clear main
456     // download manager as well.
457     if (original_notifier_.get() && original_notifier_->GetManager())
458       original_notifier_->GetManager()->RemoveAllDownloads();
459   }
460
461   // downloads.js always clears the display and relies on HandleClearAll to
462   // ScheduleSendCurrentDownloads(). If any downloads are removed, then
463   // OnDownloadRemoved() will call it, but if no downloads are actually removed,
464   // then HandleClearAll needs to call it manually.
465   ScheduleSendCurrentDownloads();
466 }
467
468 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
469     const base::ListValue* args) {
470   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER);
471   content::DownloadManager* manager = main_notifier_.GetManager();
472   if (manager) {
473     platform_util::OpenItem(
474         Profile::FromBrowserContext(manager->GetBrowserContext()),
475         DownloadPrefs::FromDownloadManager(manager)->DownloadPath());
476   }
477 }
478
479 // DownloadsDOMHandler, private: ----------------------------------------------
480
481 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() {
482   // Don't call SendCurrentDownloads() every time anything changes. Batch them
483   // together instead. This may handle hundreds of OnDownloadDestroyed() calls
484   // in a single UI message loop iteration when the user Clears All downloads.
485   if (update_scheduled_)
486     return;
487   update_scheduled_ = true;
488   BrowserThread::PostTask(
489       BrowserThread::UI, FROM_HERE,
490       base::Bind(&DownloadsDOMHandler::SendCurrentDownloads,
491                  weak_ptr_factory_.GetWeakPtr()));
492 }
493
494 void DownloadsDOMHandler::SendCurrentDownloads() {
495   update_scheduled_ = false;
496   content::DownloadManager::DownloadVector all_items, filtered_items;
497   if (main_notifier_.GetManager()) {
498     main_notifier_.GetManager()->GetAllDownloads(&all_items);
499     main_notifier_.GetManager()->CheckForHistoryFilesRemoval();
500   }
501   if (original_notifier_.get() && original_notifier_->GetManager()) {
502     original_notifier_->GetManager()->GetAllDownloads(&all_items);
503     original_notifier_->GetManager()->CheckForHistoryFilesRemoval();
504   }
505   DownloadQuery query;
506   if (search_terms_ && !search_terms_->empty()) {
507     query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_.get());
508   }
509   query.AddFilter(base::Bind(&IsDownloadDisplayable));
510   query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
511   query.Limit(kMaxDownloads);
512   query.Search(all_items.begin(), all_items.end(), &filtered_items);
513   base::ListValue results_value;
514   for (content::DownloadManager::DownloadVector::const_iterator
515        iter = filtered_items.begin(); iter != filtered_items.end(); ++iter) {
516     results_value.Append(CreateDownloadItemValue(
517         *iter,
518         (original_notifier_.get() &&
519           main_notifier_.GetManager() &&
520           (main_notifier_.GetManager()->GetDownload((*iter)->GetId()) ==
521           *iter))));
522   }
523   CallDownloadsList(results_value);
524 }
525
526 void DownloadsDOMHandler::ShowDangerPrompt(
527     content::DownloadItem* dangerous_item) {
528   DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
529       dangerous_item,
530       GetWebUIWebContents(),
531       false,
532       base::Bind(&DownloadsDOMHandler::DangerPromptDone,
533                  weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()));
534   // danger_prompt will delete itself.
535   DCHECK(danger_prompt);
536 }
537
538 void DownloadsDOMHandler::DangerPromptDone(
539     int download_id, DownloadDangerPrompt::Action action) {
540   if (action != DownloadDangerPrompt::ACCEPT)
541     return;
542   content::DownloadItem* item = NULL;
543   if (main_notifier_.GetManager())
544     item = main_notifier_.GetManager()->GetDownload(download_id);
545   if (!item && original_notifier_.get() && original_notifier_->GetManager())
546     item = original_notifier_->GetManager()->GetDownload(download_id);
547   if (!item || item->IsDone())
548     return;
549   CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
550   item->ValidateDangerousDownload();
551 }
552
553 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() {
554   content::DownloadManager* manager = main_notifier_.GetManager();
555   return (manager &&
556           Profile::FromBrowserContext(manager->GetBrowserContext())->
557               GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory));
558 }
559
560 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue(
561     const base::ListValue* args) {
562   int download_id = -1;
563   if (!ExtractIntegerValue(args, &download_id))
564     return NULL;
565   content::DownloadItem* item = NULL;
566   if (main_notifier_.GetManager())
567     item = main_notifier_.GetManager()->GetDownload(download_id);
568   if (!item && original_notifier_.get() && original_notifier_->GetManager())
569     item = original_notifier_->GetManager()->GetDownload(download_id);
570   return item;
571 }
572
573 content::WebContents* DownloadsDOMHandler::GetWebUIWebContents() {
574   return web_ui()->GetWebContents();
575 }
576
577 void DownloadsDOMHandler::CallDownloadsList(const base::ListValue& downloads) {
578   web_ui()->CallJavascriptFunction("downloadsList", downloads);
579 }
580
581 void DownloadsDOMHandler::CallDownloadUpdated(
582     const base::ListValue& download_item) {
583   web_ui()->CallJavascriptFunction("downloadUpdated", download_item);
584 }