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/logging.h"
16 #include "base/memory/singleton.h"
17 #include "base/metrics/field_trial.h"
18 #include "base/metrics/histogram.h"
19 #include "base/prefs/pref_service.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_piece.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/supports_user_data.h"
24 #include "base/threading/thread.h"
25 #include "base/value_conversions.h"
26 #include "base/values.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/download/download_crx_util.h"
29 #include "chrome/browser/download/download_danger_prompt.h"
30 #include "chrome/browser/download/download_history.h"
31 #include "chrome/browser/download/download_item_model.h"
32 #include "chrome/browser/download/download_prefs.h"
33 #include "chrome/browser/download/download_query.h"
34 #include "chrome/browser/download/download_service.h"
35 #include "chrome/browser/download/download_service_factory.h"
36 #include "chrome/browser/download/drag_download_item.h"
37 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
38 #include "chrome/browser/extensions/extension_service.h"
39 #include "chrome/browser/platform_util.h"
40 #include "chrome/browser/profiles/profile.h"
41 #include "chrome/browser/ui/webui/fileicon_source.h"
42 #include "chrome/common/chrome_switches.h"
43 #include "chrome/common/pref_names.h"
44 #include "chrome/common/url_constants.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/download_item.h"
47 #include "content/public/browser/url_data_source.h"
48 #include "content/public/browser/user_metrics.h"
49 #include "content/public/browser/web_contents.h"
50 #include "content/public/browser/web_ui.h"
51 #include "extensions/browser/extension_system.h"
52 #include "net/base/filename_util.h"
53 #include "ui/base/l10n/time_format.h"
54 #include "ui/gfx/image/image.h"
56 using base::UserMetricsAction
;
57 using content::BrowserContext
;
58 using content::BrowserThread
;
62 // Maximum number of downloads to show. TODO(glen): Remove this and instead
63 // stuff the downloads down the pipe slowly.
64 static const size_t kMaxDownloads
= 150;
66 enum DownloadsDOMEvent
{
67 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS
= 0,
68 DOWNLOADS_DOM_EVENT_OPEN_FILE
= 1,
69 DOWNLOADS_DOM_EVENT_DRAG
= 2,
70 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS
= 3,
71 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS
= 4,
72 DOWNLOADS_DOM_EVENT_SHOW
= 5,
73 DOWNLOADS_DOM_EVENT_PAUSE
= 6,
74 DOWNLOADS_DOM_EVENT_REMOVE
= 7,
75 DOWNLOADS_DOM_EVENT_CANCEL
= 8,
76 DOWNLOADS_DOM_EVENT_CLEAR_ALL
= 9,
77 DOWNLOADS_DOM_EVENT_OPEN_FOLDER
= 10,
78 DOWNLOADS_DOM_EVENT_RESUME
= 11,
79 DOWNLOADS_DOM_EVENT_MAX
82 void CountDownloadsDOMEvents(DownloadsDOMEvent event
) {
83 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
85 DOWNLOADS_DOM_EVENT_MAX
);
88 // Returns a string constant to be used as the |danger_type| value in
89 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
90 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
91 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
92 const char* GetDangerTypeString(content::DownloadDangerType danger_type
) {
93 switch (danger_type
) {
94 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
95 return "DANGEROUS_FILE";
96 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
97 return "DANGEROUS_URL";
98 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
99 return "DANGEROUS_CONTENT";
100 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
101 return "UNCOMMON_CONTENT";
102 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
103 return "DANGEROUS_HOST";
104 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
:
105 return "POTENTIALLY_UNWANTED";
107 // Don't return a danger type string if it is NOT_DANGEROUS or
108 // MAYBE_DANGEROUS_CONTENT.
114 // Returns a JSON dictionary containing some of the attributes of |download|.
115 // The JSON dictionary will also have a field "id" set to |id|, and a field
116 // "otr" set to |incognito|.
117 base::DictionaryValue
* CreateDownloadItemValue(
118 content::DownloadItem
* download_item
,
120 // TODO(asanka): Move towards using download_model here for getting status and
121 // progress. The difference currently only matters to Drive downloads and
122 // those don't show up on the downloads page, but should.
123 DownloadItemModel
download_model(download_item
);
125 // The items which are to be written into file_value are also described in
126 // chrome/browser/resources/downloads/downloads.js in @typedef for
127 // BackendDownloadObject. Please update it whenever you add or remove
128 // any keys in file_value.
129 base::DictionaryValue
* file_value
= new base::DictionaryValue();
131 file_value
->SetInteger(
132 "started", static_cast<int>(download_item
->GetStartTime().ToTimeT()));
133 file_value
->SetString(
134 "since_string", ui::TimeFormat::RelativeDate(
135 download_item
->GetStartTime(), NULL
));
136 file_value
->SetString(
137 "date_string", base::TimeFormatShortDate(download_item
->GetStartTime()));
138 file_value
->SetString("id", base::Uint64ToString(download_item
->GetId()));
140 base::FilePath
download_path(download_item
->GetTargetFilePath());
141 file_value
->Set("file_path", base::CreateFilePathValue(download_path
));
142 file_value
->SetString("file_url",
143 net::FilePathToFileURL(download_path
).spec());
145 extensions::DownloadedByExtension
* by_ext
=
146 extensions::DownloadedByExtension::Get(download_item
);
148 file_value
->SetString("by_ext_id", by_ext
->id());
149 file_value
->SetString("by_ext_name", by_ext
->name());
150 // Lookup the extension's current name() in case the user changed their
151 // language. This won't work if the extension was uninstalled, so the name
152 // might be the wrong language.
153 bool include_disabled
= true;
154 const extensions::Extension
* extension
= extensions::ExtensionSystem::Get(
155 Profile::FromBrowserContext(download_item
->GetBrowserContext()))->
156 extension_service()->GetExtensionById(by_ext
->id(), include_disabled
);
158 file_value
->SetString("by_ext_name", extension
->name());
161 // Keep file names as LTR.
162 base::string16 file_name
=
163 download_item
->GetFileNameToReportUser().LossyDisplayName();
164 file_name
= base::i18n::GetDisplayStringInLTRDirectionality(file_name
);
165 file_value
->SetString("file_name", file_name
);
166 file_value
->SetString("url", download_item
->GetURL().spec());
167 file_value
->SetBoolean("otr", incognito
);
168 file_value
->SetInteger("total", static_cast<int>(
169 download_item
->GetTotalBytes()));
170 file_value
->SetBoolean("file_externally_removed",
171 download_item
->GetFileExternallyRemoved());
172 file_value
->SetBoolean("retry", false); // Overridden below if needed.
173 file_value
->SetBoolean("resume", download_item
->CanResume());
175 switch (download_item
->GetState()) {
176 case content::DownloadItem::IN_PROGRESS
: {
177 if (download_item
->IsDangerous()) {
178 file_value
->SetString("state", "DANGEROUS");
179 // These are the only danger states that the UI is equipped to handle.
180 DCHECK(download_item
->GetDangerType() ==
181 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
||
182 download_item
->GetDangerType() ==
183 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
||
184 download_item
->GetDangerType() ==
185 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
||
186 download_item
->GetDangerType() ==
187 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
||
188 download_item
->GetDangerType() ==
189 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
||
190 download_item
->GetDangerType() ==
191 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
);
192 const char* danger_type_value
=
193 GetDangerTypeString(download_item
->GetDangerType());
194 file_value
->SetString("danger_type", danger_type_value
);
195 } else if (download_item
->IsPaused()) {
196 file_value
->SetString("state", "PAUSED");
198 file_value
->SetString("state", "IN_PROGRESS");
200 file_value
->SetString("progress_status_text",
201 download_model
.GetTabProgressStatusText());
203 int percent
= download_item
->PercentComplete();
204 if (!switches::MdDownloadsEnabled())
205 percent
= std::max(0, percent
);
206 file_value
->SetInteger("percent", percent
);
208 file_value
->SetInteger("received",
209 static_cast<int>(download_item
->GetReceivedBytes()));
213 case content::DownloadItem::INTERRUPTED
:
214 file_value
->SetString("state", "INTERRUPTED");
216 file_value
->SetString("progress_status_text",
217 download_model
.GetTabProgressStatusText());
219 file_value
->SetInteger("percent",
220 static_cast<int>(download_item
->PercentComplete()));
221 file_value
->SetInteger("received",
222 static_cast<int>(download_item
->GetReceivedBytes()));
223 file_value
->SetString("last_reason_text",
224 download_model
.GetInterruptReasonText());
225 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH
==
226 download_item
->GetLastReason() && !download_item
->CanResume())
227 file_value
->SetBoolean("retry", true);
230 case content::DownloadItem::CANCELLED
:
231 file_value
->SetString("state", "CANCELLED");
232 file_value
->SetBoolean("retry", true);
235 case content::DownloadItem::COMPLETE
:
236 DCHECK(!download_item
->IsDangerous());
237 file_value
->SetString("state", "COMPLETE");
240 case content::DownloadItem::MAX_DOWNLOAD_STATE
:
247 // Filters out extension downloads and downloads that don't have a filename yet.
248 bool IsDownloadDisplayable(const content::DownloadItem
& item
) {
249 return !download_crx_util::IsExtensionDownload(item
) &&
250 !item
.IsTemporary() &&
251 !item
.GetFileNameToReportUser().empty() &&
252 !item
.GetTargetFilePath().empty() &&
254 const_cast<content::DownloadItem
*>(&item
)).ShouldShowInShelf();
259 DownloadsDOMHandler::DownloadsDOMHandler(
260 content::DownloadManager
* download_manager
)
261 : download_manager_(download_manager
),
262 update_scheduled_(false),
263 weak_ptr_factory_(this) {
264 // Create our fileicon data source.
265 Profile
* profile
= Profile::FromBrowserContext(
266 download_manager
->GetBrowserContext());
267 content::URLDataSource::Add(profile
, new FileIconSource());
270 DownloadsDOMHandler::~DownloadsDOMHandler() {
274 // DownloadsDOMHandler, public: -----------------------------------------------
276 void DownloadsDOMHandler::RegisterMessages() {
277 web_ui()->RegisterMessageCallback("getDownloads",
278 base::Bind(&DownloadsDOMHandler::HandleGetDownloads
,
279 weak_ptr_factory_
.GetWeakPtr()));
280 web_ui()->RegisterMessageCallback("openFile",
281 base::Bind(&DownloadsDOMHandler::HandleOpenFile
,
282 weak_ptr_factory_
.GetWeakPtr()));
283 web_ui()->RegisterMessageCallback("drag",
284 base::Bind(&DownloadsDOMHandler::HandleDrag
,
285 weak_ptr_factory_
.GetWeakPtr()));
286 web_ui()->RegisterMessageCallback("saveDangerous",
287 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous
,
288 weak_ptr_factory_
.GetWeakPtr()));
289 web_ui()->RegisterMessageCallback("discardDangerous",
290 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous
,
291 weak_ptr_factory_
.GetWeakPtr()));
292 web_ui()->RegisterMessageCallback("show",
293 base::Bind(&DownloadsDOMHandler::HandleShow
,
294 weak_ptr_factory_
.GetWeakPtr()));
295 web_ui()->RegisterMessageCallback("pause",
296 base::Bind(&DownloadsDOMHandler::HandlePause
,
297 weak_ptr_factory_
.GetWeakPtr()));
298 web_ui()->RegisterMessageCallback("resume",
299 base::Bind(&DownloadsDOMHandler::HandleResume
,
300 weak_ptr_factory_
.GetWeakPtr()));
301 web_ui()->RegisterMessageCallback("remove",
302 base::Bind(&DownloadsDOMHandler::HandleRemove
,
303 weak_ptr_factory_
.GetWeakPtr()));
304 web_ui()->RegisterMessageCallback("undo",
305 base::Bind(&DownloadsDOMHandler::HandleUndo
,
306 weak_ptr_factory_
.GetWeakPtr()));
307 web_ui()->RegisterMessageCallback("cancel",
308 base::Bind(&DownloadsDOMHandler::HandleCancel
,
309 weak_ptr_factory_
.GetWeakPtr()));
310 web_ui()->RegisterMessageCallback("clearAll",
311 base::Bind(&DownloadsDOMHandler::HandleClearAll
,
312 weak_ptr_factory_
.GetWeakPtr()));
313 web_ui()->RegisterMessageCallback("openDownloadsFolder",
314 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder
,
315 weak_ptr_factory_
.GetWeakPtr()));
318 void DownloadsDOMHandler::OnDownloadCreated(
319 content::DownloadManager
* manager
, content::DownloadItem
* download_item
) {
320 if (IsDownloadDisplayable(*download_item
))
321 ScheduleSendCurrentDownloads();
323 new_downloads_
.insert(download_item
->GetId());
326 void DownloadsDOMHandler::OnDownloadUpdated(
327 content::DownloadManager
* manager
,
328 content::DownloadItem
* download_item
) {
329 if (update_scheduled_
)
332 bool showing_new_item
= false;
334 if (new_downloads_
.count(download_item
->GetId())) {
335 // A new download (that the page doesn't know about yet) has been updated.
336 if (!IsDownloadDisplayable(*download_item
)) {
337 // Item isn't ready to be displayed yet. Wait until it is.
341 new_downloads_
.erase(download_item
->GetId());
342 showing_new_item
= true;
345 if (showing_new_item
|| DownloadItemModel(download_item
).IsBeingRevived() ||
346 !IsDownloadDisplayable(*download_item
)) {
347 // A download will be shown or hidden by this update. Resend the list.
348 ScheduleSendCurrentDownloads();
352 if (search_terms_
&& !search_terms_
->empty()) {
353 // Don't CallUpdateItem() if download_item doesn't match
355 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
356 content::DownloadManager::DownloadVector all_items
, filtered_items
;
357 all_items
.push_back(download_item
);
359 query
.AddFilter(DownloadQuery::FILTER_QUERY
, *search_terms_
);
360 query
.Search(all_items
.begin(), all_items
.end(), &filtered_items
);
361 if (filtered_items
.empty())
366 scoped_ptr
<base::DictionaryValue
> item(CreateDownloadItemValue(
368 original_notifier_
&& manager
== GetMainNotifierManager()));
369 CallUpdateItem(*item
);
372 void DownloadsDOMHandler::OnDownloadRemoved(
373 content::DownloadManager
* manager
,
374 content::DownloadItem
* download_item
) {
375 if (!DownloadItemModel(download_item
).ShouldShowInShelf())
378 // This relies on |download_item| being removed from DownloadManager in this
379 // MessageLoop iteration. |download_item| may not have been removed from
380 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
381 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
382 // at all downloads, and we do not tell it that |download_item| is being
383 // removed. If DownloadManager is ever changed to not immediately remove
384 // |download_item| from its map when OnDownloadRemoved is sent, then
385 // DownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
386 // SendCurrentDownloads() that |download_item| was removed. A
387 // SupportsUserData::Data would be the correct way to do this.
388 ScheduleSendCurrentDownloads();
391 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue
* args
) {
392 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS
);
393 search_terms_
.reset(args
&& !args
->empty() ? args
->DeepCopy() : NULL
);
394 ScheduleSendCurrentDownloads();
396 if (!main_notifier_
) {
397 main_notifier_
.reset(new AllDownloadItemNotifier(download_manager_
, this));
399 Profile
* profile
= Profile::FromBrowserContext(
400 download_manager_
->GetBrowserContext());
401 if (profile
->IsOffTheRecord()) {
402 original_notifier_
.reset(new AllDownloadItemNotifier(
403 BrowserContext::GetDownloadManager(profile
->GetOriginalProfile()),
409 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue
* args
) {
410 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE
);
411 content::DownloadItem
* file
= GetDownloadByValue(args
);
413 file
->OpenDownload();
416 void DownloadsDOMHandler::HandleDrag(const base::ListValue
* args
) {
417 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG
);
418 content::DownloadItem
* file
= GetDownloadByValue(args
);
422 content::WebContents
* web_contents
= GetWebUIWebContents();
423 // |web_contents| is only NULL in the test.
427 if (file
->GetState() != content::DownloadItem::COMPLETE
)
430 gfx::Image
* icon
= g_browser_process
->icon_manager()->LookupIconFromFilepath(
431 file
->GetTargetFilePath(), IconLoader::NORMAL
);
432 gfx::NativeView view
= web_contents
->GetNativeView();
434 // Enable nested tasks during DnD, while |DragDownload()| blocks.
435 base::MessageLoop::ScopedNestableTaskAllower
allow(
436 base::MessageLoop::current());
437 DragDownloadItem(file
, icon
, view
);
441 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue
* args
) {
442 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS
);
443 content::DownloadItem
* file
= GetDownloadByValue(args
);
445 ShowDangerPrompt(file
);
448 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue
* args
) {
449 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS
);
450 content::DownloadItem
* file
= GetDownloadByValue(args
);
455 void DownloadsDOMHandler::HandleShow(const base::ListValue
* args
) {
456 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW
);
457 content::DownloadItem
* file
= GetDownloadByValue(args
);
459 file
->ShowDownloadInShell();
462 void DownloadsDOMHandler::HandlePause(const base::ListValue
* args
) {
463 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE
);
464 content::DownloadItem
* file
= GetDownloadByValue(args
);
469 void DownloadsDOMHandler::HandleResume(const base::ListValue
* args
) {
470 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME
);
471 content::DownloadItem
* file
= GetDownloadByValue(args
);
476 void DownloadsDOMHandler::HandleRemove(const base::ListValue
* args
) {
477 if (!IsDeletingHistoryAllowed())
480 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE
);
481 content::DownloadItem
* file
= GetDownloadByValue(args
);
485 std::vector
<content::DownloadItem
*> downloads
;
486 downloads
.push_back(file
);
487 RemoveDownloads(downloads
);
490 void DownloadsDOMHandler::HandleUndo(const base::ListValue
* args
) {
491 // TODO(dbeam): handle more than removed downloads someday?
492 if (removals_
.empty())
495 const std::set
<uint32
> last_removed_ids
= removals_
.back();
496 removals_
.pop_back();
498 for (auto id
: last_removed_ids
) {
499 content::DownloadItem
* download
= GetDownloadById(id
);
503 DownloadItemModel
model(download
);
504 model
.SetShouldShowInShelf(true);
505 model
.SetIsBeingRevived(true);
507 download
->UpdateObservers();
509 model
.SetIsBeingRevived(false);
513 void DownloadsDOMHandler::HandleCancel(const base::ListValue
* args
) {
514 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL
);
515 content::DownloadItem
* file
= GetDownloadByValue(args
);
520 void DownloadsDOMHandler::HandleClearAll(const base::ListValue
* args
) {
521 if (!IsDeletingHistoryAllowed()) {
522 // This should only be reached during tests.
526 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL
);
528 std::vector
<content::DownloadItem
*> downloads
;
529 if (GetMainNotifierManager())
530 GetMainNotifierManager()->GetAllDownloads(&downloads
);
531 if (GetOriginalNotifierManager())
532 GetOriginalNotifierManager()->GetAllDownloads(&downloads
);
533 RemoveDownloads(downloads
);
536 void DownloadsDOMHandler::RemoveDownloads(
537 const std::vector
<content::DownloadItem
*>& to_remove
) {
538 std::set
<uint32
> ids
;
540 for (auto* download
: to_remove
) {
541 DownloadItemModel
item_model(download
);
542 if (!item_model
.ShouldShowInShelf() ||
543 download
->GetState() == content::DownloadItem::IN_PROGRESS
) {
547 item_model
.SetShouldShowInShelf(false);
548 ids
.insert(download
->GetId());
549 download
->UpdateObservers();
553 removals_
.push_back(ids
);
556 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
557 const base::ListValue
* args
) {
558 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER
);
559 content::DownloadManager
* manager
= GetMainNotifierManager();
561 platform_util::OpenItem(
562 Profile::FromBrowserContext(manager
->GetBrowserContext()),
563 DownloadPrefs::FromDownloadManager(manager
)->DownloadPath(),
564 platform_util::OPEN_FOLDER
, platform_util::OpenOperationCallback());
568 // DownloadsDOMHandler, private: ----------------------------------------------
570 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() {
571 // Don't call SendCurrentDownloads() every time anything changes. Batch them
572 // together instead. This may handle hundreds of OnDownloadDestroyed() calls
573 // in a single UI message loop iteration when the user Clears All downloads.
574 if (update_scheduled_
)
577 update_scheduled_
= true;
579 BrowserThread::PostTask(
580 BrowserThread::UI
, FROM_HERE
,
581 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads
,
582 weak_ptr_factory_
.GetWeakPtr()));
585 content::DownloadManager
* DownloadsDOMHandler::GetMainNotifierManager() const {
586 return main_notifier_
? main_notifier_
->GetManager() : nullptr;
589 content::DownloadManager
* DownloadsDOMHandler::GetOriginalNotifierManager()
591 return original_notifier_
? original_notifier_
->GetManager() : nullptr;
594 void DownloadsDOMHandler::FinalizeRemovals() {
595 while (!removals_
.empty()) {
596 const std::set
<uint32
> remove
= removals_
.back();
597 removals_
.pop_back();
599 for (const auto id
: remove
) {
600 content::DownloadItem
* download
= GetDownloadById(id
);
607 void DownloadsDOMHandler::SendCurrentDownloads() {
608 update_scheduled_
= false;
610 content::DownloadManager::DownloadVector all_items
, filtered_items
;
611 if (GetMainNotifierManager()) {
612 GetMainNotifierManager()->GetAllDownloads(&all_items
);
613 GetMainNotifierManager()->CheckForHistoryFilesRemoval();
615 if (GetOriginalNotifierManager()) {
616 GetOriginalNotifierManager()->GetAllDownloads(&all_items
);
617 GetOriginalNotifierManager()->CheckForHistoryFilesRemoval();
621 if (search_terms_
&& !search_terms_
->empty())
622 query
.AddFilter(DownloadQuery::FILTER_QUERY
, *search_terms_
);
623 query
.AddFilter(base::Bind(&IsDownloadDisplayable
));
624 query
.AddSorter(DownloadQuery::SORT_START_TIME
, DownloadQuery::DESCENDING
);
625 query
.Limit(kMaxDownloads
);
626 query
.Search(all_items
.begin(), all_items
.end(), &filtered_items
);
628 base::ListValue results_value
;
629 for (auto* item
: filtered_items
) {
630 results_value
.Append(CreateDownloadItemValue(
632 original_notifier_
&& GetMainNotifierManager() &&
633 GetMainNotifierManager()->GetDownload(item
->GetId()) == item
));
635 CallUpdateAll(results_value
);
638 void DownloadsDOMHandler::ShowDangerPrompt(
639 content::DownloadItem
* dangerous_item
) {
640 DownloadDangerPrompt
* danger_prompt
= DownloadDangerPrompt::Create(
642 GetWebUIWebContents(),
644 base::Bind(&DownloadsDOMHandler::DangerPromptDone
,
645 weak_ptr_factory_
.GetWeakPtr(), dangerous_item
->GetId()));
646 // danger_prompt will delete itself.
647 DCHECK(danger_prompt
);
650 void DownloadsDOMHandler::DangerPromptDone(
651 int download_id
, DownloadDangerPrompt::Action action
) {
652 if (action
!= DownloadDangerPrompt::ACCEPT
)
654 content::DownloadItem
* item
= NULL
;
655 if (GetMainNotifierManager())
656 item
= GetMainNotifierManager()->GetDownload(download_id
);
657 if (!item
&& GetOriginalNotifierManager())
658 item
= GetOriginalNotifierManager()->GetDownload(download_id
);
659 if (!item
|| item
->IsDone())
661 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS
);
662 item
->ValidateDangerousDownload();
665 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() {
666 content::DownloadManager
* manager
= GetMainNotifierManager();
668 Profile::FromBrowserContext(manager
->GetBrowserContext())->
669 GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory
);
672 content::DownloadItem
* DownloadsDOMHandler::GetDownloadByValue(
673 const base::ListValue
* args
) {
674 std::string download_id
;
675 if (!args
->GetString(0, &download_id
)) {
681 if (!base::StringToUint64(download_id
, &id
)) {
686 return GetDownloadById(static_cast<uint32
>(id
));
689 content::DownloadItem
* DownloadsDOMHandler::GetDownloadById(uint32 id
) {
690 content::DownloadItem
* item
= NULL
;
691 if (GetMainNotifierManager())
692 item
= GetMainNotifierManager()->GetDownload(id
);
693 if (!item
&& GetOriginalNotifierManager())
694 item
= GetOriginalNotifierManager()->GetDownload(id
);
698 content::WebContents
* DownloadsDOMHandler::GetWebUIWebContents() {
699 return web_ui()->GetWebContents();
702 void DownloadsDOMHandler::CallUpdateAll(const base::ListValue
& list
) {
703 web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list
);
706 void DownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue
& item
) {
707 web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item
);