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/ui/webui/downloads_dom_handler.h"
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/extensions/extension_system.h"
37 #include "chrome/browser/platform_util.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/ui/webui/fileicon_source.h"
40 #include "chrome/common/pref_names.h"
41 #include "chrome/common/url_constants.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/download_item.h"
44 #include "content/public/browser/url_data_source.h"
45 #include "content/public/browser/user_metrics.h"
46 #include "content/public/browser/web_contents.h"
47 #include "content/public/browser/web_contents_view.h"
48 #include "content/public/browser/web_ui.h"
49 #include "grit/generated_resources.h"
50 #include "net/base/net_util.h"
51 #include "ui/base/l10n/time_format.h"
52 #include "ui/gfx/image/image.h"
54 using base::UserMetricsAction
;
55 using content::BrowserContext
;
56 using content::BrowserThread
;
60 // Maximum number of downloads to show. TODO(glen): Remove this and instead
61 // stuff the downloads down the pipe slowly.
62 static const size_t kMaxDownloads
= 150;
64 enum DownloadsDOMEvent
{
65 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS
= 0,
66 DOWNLOADS_DOM_EVENT_OPEN_FILE
= 1,
67 DOWNLOADS_DOM_EVENT_DRAG
= 2,
68 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS
= 3,
69 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS
= 4,
70 DOWNLOADS_DOM_EVENT_SHOW
= 5,
71 DOWNLOADS_DOM_EVENT_PAUSE
= 6,
72 DOWNLOADS_DOM_EVENT_REMOVE
= 7,
73 DOWNLOADS_DOM_EVENT_CANCEL
= 8,
74 DOWNLOADS_DOM_EVENT_CLEAR_ALL
= 9,
75 DOWNLOADS_DOM_EVENT_OPEN_FOLDER
= 10,
76 DOWNLOADS_DOM_EVENT_RESUME
= 11,
77 DOWNLOADS_DOM_EVENT_MAX
80 void CountDownloadsDOMEvents(DownloadsDOMEvent event
) {
81 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
83 DOWNLOADS_DOM_EVENT_MAX
);
86 // Returns a string constant to be used as the |danger_type| value in
87 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
88 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
89 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
90 const char* GetDangerTypeString(content::DownloadDangerType danger_type
) {
91 switch (danger_type
) {
92 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
93 return "DANGEROUS_FILE";
94 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
95 return "DANGEROUS_URL";
96 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
97 return "DANGEROUS_CONTENT";
98 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
99 return "UNCOMMON_CONTENT";
100 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
101 return "DANGEROUS_HOST";
102 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
:
103 return "POTENTIALLY_UNWANTED";
105 // Don't return a danger type string if it is NOT_DANGEROUS or
106 // MAYBE_DANGEROUS_CONTENT.
112 // Returns a JSON dictionary containing some of the attributes of |download|.
113 // The JSON dictionary will also have a field "id" set to |id|, and a field
114 // "otr" set to |incognito|.
115 base::DictionaryValue
* CreateDownloadItemValue(
116 content::DownloadItem
* download_item
,
118 // TODO(asanka): Move towards using download_model here for getting status and
119 // progress. The difference currently only matters to Drive downloads and
120 // those don't show up on the downloads page, but should.
121 DownloadItemModel
download_model(download_item
);
122 base::DictionaryValue
* file_value
= new base::DictionaryValue();
124 file_value
->SetInteger(
125 "started", static_cast<int>(download_item
->GetStartTime().ToTimeT()));
126 file_value
->SetString(
127 "since_string", ui::TimeFormat::RelativeDate(
128 download_item
->GetStartTime(), NULL
));
129 file_value
->SetString(
130 "date_string", base::TimeFormatShortDate(download_item
->GetStartTime()));
131 file_value
->SetInteger("id", download_item
->GetId());
133 base::FilePath
download_path(download_item
->GetTargetFilePath());
134 file_value
->Set("file_path", base::CreateFilePathValue(download_path
));
135 file_value
->SetString("file_url",
136 net::FilePathToFileURL(download_path
).spec());
138 DownloadedByExtension
* by_ext
= DownloadedByExtension::Get(download_item
);
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
);
150 file_value
->SetString("by_ext_name", extension
->name());
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());
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");
190 file_value
->SetString("state", "IN_PROGRESS");
192 file_value
->SetString("progress_status_text",
193 download_model
.GetTabProgressStatusText());
195 file_value
->SetInteger("percent",
196 static_cast<int>(download_item
->PercentComplete()));
197 file_value
->SetInteger("received",
198 static_cast<int>(download_item
->GetReceivedBytes()));
201 case content::DownloadItem::INTERRUPTED
:
202 file_value
->SetString("state", "INTERRUPTED");
204 file_value
->SetString("progress_status_text",
205 download_model
.GetTabProgressStatusText());
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);
218 case content::DownloadItem::CANCELLED
:
219 file_value
->SetString("state", "CANCELLED");
220 file_value
->SetBoolean("retry", true);
223 case content::DownloadItem::COMPLETE
:
224 DCHECK(!download_item
->IsDangerous());
225 file_value
->SetString("state", "COMPLETE");
228 case content::DownloadItem::MAX_DOWNLOAD_STATE
:
229 NOTREACHED() << "state undefined";
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());
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());
253 if (profile
->IsOffTheRecord()) {
254 original_notifier_
.reset(new AllDownloadItemNotifier(
255 BrowserContext::GetDownloadManager(profile
->GetOriginalProfile()),
260 DownloadsDOMHandler::~DownloadsDOMHandler() {
263 // DownloadsDOMHandler, public: -----------------------------------------------
265 void DownloadsDOMHandler::OnPageLoaded(const base::ListValue
* args
) {
266 SendCurrentDownloads();
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()));
311 void DownloadsDOMHandler::OnDownloadCreated(
312 content::DownloadManager
* manager
, content::DownloadItem
* download_item
) {
313 if (IsDownloadDisplayable(*download_item
))
314 ScheduleSendCurrentDownloads();
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
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
);
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())
333 base::ListValue results_value
;
334 results_value
.Append(CreateDownloadItemValue(
336 (original_notifier_
.get() &&
337 (manager
== main_notifier_
.GetManager()))));
338 CallDownloadUpdated(results_value
);
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();
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();
364 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue
* args
) {
365 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE
);
366 content::DownloadItem
* file
= GetDownloadByValue(args
);
368 file
->OpenDownload();
371 void DownloadsDOMHandler::HandleDrag(const base::ListValue
* args
) {
372 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG
);
373 content::DownloadItem
* file
= GetDownloadByValue(args
);
377 content::WebContents
* web_contents
= GetWebUIWebContents();
378 // |web_contents| is only NULL in the test.
382 if (file
->GetState() != content::DownloadItem::COMPLETE
)
385 gfx::Image
* icon
= g_browser_process
->icon_manager()->LookupIconFromFilepath(
386 file
->GetTargetFilePath(), IconLoader::NORMAL
);
387 gfx::NativeView view
= web_contents
->GetView()->GetNativeView();
389 // Enable nested tasks during DnD, while |DragDownload()| blocks.
390 base::MessageLoop::ScopedNestableTaskAllower
allow(
391 base::MessageLoop::current());
392 DragDownloadItem(file
, icon
, view
);
396 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue
* args
) {
397 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS
);
398 content::DownloadItem
* file
= GetDownloadByValue(args
);
400 ShowDangerPrompt(file
);
403 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue
* args
) {
404 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS
);
405 content::DownloadItem
* file
= GetDownloadByValue(args
);
410 void DownloadsDOMHandler::HandleShow(const base::ListValue
* args
) {
411 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW
);
412 content::DownloadItem
* file
= GetDownloadByValue(args
);
414 file
->ShowDownloadInShell();
417 void DownloadsDOMHandler::HandlePause(const base::ListValue
* args
) {
418 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE
);
419 content::DownloadItem
* file
= GetDownloadByValue(args
);
424 void DownloadsDOMHandler::HandleResume(const base::ListValue
* args
) {
425 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME
);
426 content::DownloadItem
* file
= GetDownloadByValue(args
);
431 void DownloadsDOMHandler::HandleRemove(const base::ListValue
* args
) {
432 if (!IsDeletingHistoryAllowed())
435 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE
);
436 content::DownloadItem
* file
= GetDownloadByValue(args
);
441 void DownloadsDOMHandler::HandleCancel(const base::ListValue
* args
) {
442 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL
);
443 content::DownloadItem
* file
= GetDownloadByValue(args
);
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
453 main_notifier_
.GetManager()->RemoveAllDownloads();
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();
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();
468 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
469 const base::ListValue
* args
) {
470 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER
);
471 content::DownloadManager
* manager
= main_notifier_
.GetManager();
473 platform_util::OpenItem(
474 Profile::FromBrowserContext(manager
->GetBrowserContext()),
475 DownloadPrefs::FromDownloadManager(manager
)->DownloadPath());
479 // DownloadsDOMHandler, private: ----------------------------------------------
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_
)
487 update_scheduled_
= true;
488 BrowserThread::PostTask(
489 BrowserThread::UI
, FROM_HERE
,
490 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads
,
491 weak_ptr_factory_
.GetWeakPtr()));
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();
501 if (original_notifier_
.get() && original_notifier_
->GetManager()) {
502 original_notifier_
->GetManager()->GetAllDownloads(&all_items
);
503 original_notifier_
->GetManager()->CheckForHistoryFilesRemoval();
506 if (search_terms_
&& !search_terms_
->empty()) {
507 query
.AddFilter(DownloadQuery::FILTER_QUERY
, *search_terms_
.get());
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(
518 (original_notifier_
.get() &&
519 main_notifier_
.GetManager() &&
520 (main_notifier_
.GetManager()->GetDownload((*iter
)->GetId()) ==
523 CallDownloadsList(results_value
);
526 void DownloadsDOMHandler::ShowDangerPrompt(
527 content::DownloadItem
* dangerous_item
) {
528 DownloadDangerPrompt
* danger_prompt
= DownloadDangerPrompt::Create(
530 GetWebUIWebContents(),
532 base::Bind(&DownloadsDOMHandler::DangerPromptDone
,
533 weak_ptr_factory_
.GetWeakPtr(), dangerous_item
->GetId()));
534 // danger_prompt will delete itself.
535 DCHECK(danger_prompt
);
538 void DownloadsDOMHandler::DangerPromptDone(
539 int download_id
, DownloadDangerPrompt::Action action
) {
540 if (action
!= DownloadDangerPrompt::ACCEPT
)
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())
549 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS
);
550 item
->ValidateDangerousDownload();
553 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() {
554 content::DownloadManager
* manager
= main_notifier_
.GetManager();
556 Profile::FromBrowserContext(manager
->GetBrowserContext())->
557 GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory
));
560 content::DownloadItem
* DownloadsDOMHandler::GetDownloadByValue(
561 const base::ListValue
* args
) {
562 int download_id
= -1;
563 if (!ExtractIntegerValue(args
, &download_id
))
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
);
573 content::WebContents
* DownloadsDOMHandler::GetWebUIWebContents() {
574 return web_ui()->GetWebContents();
577 void DownloadsDOMHandler::CallDownloadsList(const base::ListValue
& downloads
) {
578 web_ui()->CallJavascriptFunction("downloadsList", downloads
);
581 void DownloadsDOMHandler::CallDownloadUpdated(
582 const base::ListValue
& download_item
) {
583 web_ui()->CallJavascriptFunction("downloadUpdated", download_item
);