Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / webui / downloads_dom_handler.cc
blob7ffbe76a169af2aa1cbe91619ae5c8d99ae4e7f8
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"
7 #include <algorithm>
8 #include <functional>
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/pref_names.h"
43 #include "chrome/common/url_constants.h"
44 #include "content/public/browser/browser_thread.h"
45 #include "content/public/browser/download_item.h"
46 #include "content/public/browser/url_data_source.h"
47 #include "content/public/browser/user_metrics.h"
48 #include "content/public/browser/web_contents.h"
49 #include "content/public/browser/web_ui.h"
50 #include "extensions/browser/extension_system.h"
51 #include "net/base/filename_util.h"
52 #include "ui/base/l10n/time_format.h"
53 #include "ui/gfx/image/image.h"
55 using base::UserMetricsAction;
56 using content::BrowserContext;
57 using content::BrowserThread;
59 namespace {
61 // Maximum number of downloads to show. TODO(glen): Remove this and instead
62 // stuff the downloads down the pipe slowly.
63 static const size_t kMaxDownloads = 150;
65 enum DownloadsDOMEvent {
66 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
67 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
68 DOWNLOADS_DOM_EVENT_DRAG = 2,
69 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3,
70 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4,
71 DOWNLOADS_DOM_EVENT_SHOW = 5,
72 DOWNLOADS_DOM_EVENT_PAUSE = 6,
73 DOWNLOADS_DOM_EVENT_REMOVE = 7,
74 DOWNLOADS_DOM_EVENT_CANCEL = 8,
75 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9,
76 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10,
77 DOWNLOADS_DOM_EVENT_RESUME = 11,
78 DOWNLOADS_DOM_EVENT_MAX
81 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
82 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
83 event,
84 DOWNLOADS_DOM_EVENT_MAX);
87 // Returns a string constant to be used as the |danger_type| value in
88 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
89 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
90 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
91 const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
92 switch (danger_type) {
93 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
94 return "DANGEROUS_FILE";
95 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
96 return "DANGEROUS_URL";
97 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
98 return "DANGEROUS_CONTENT";
99 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
100 return "UNCOMMON_CONTENT";
101 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
102 return "DANGEROUS_HOST";
103 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
104 return "POTENTIALLY_UNWANTED";
105 default:
106 // Don't return a danger type string if it is NOT_DANGEROUS or
107 // MAYBE_DANGEROUS_CONTENT.
108 NOTREACHED();
109 return "";
113 // Returns a JSON dictionary containing some of the attributes of |download|.
114 // The JSON dictionary will also have a field "id" set to |id|, and a field
115 // "otr" set to |incognito|.
116 base::DictionaryValue* CreateDownloadItemValue(
117 content::DownloadItem* download_item,
118 bool incognito) {
119 // TODO(asanka): Move towards using download_model here for getting status and
120 // progress. The difference currently only matters to Drive downloads and
121 // those don't show up on the downloads page, but should.
122 DownloadItemModel download_model(download_item);
124 // The items which are to be written into file_value are also described in
125 // chrome/browser/resources/downloads/downloads.js in @typedef for
126 // BackendDownloadObject. Please update it whenever you add or remove
127 // any keys in file_value.
128 base::DictionaryValue* file_value = new base::DictionaryValue();
130 file_value->SetInteger(
131 "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
132 file_value->SetString(
133 "since_string", ui::TimeFormat::RelativeDate(
134 download_item->GetStartTime(), NULL));
135 file_value->SetString(
136 "date_string", base::TimeFormatShortDate(download_item->GetStartTime()));
137 file_value->SetString("id", base::Uint64ToString(download_item->GetId()));
139 base::FilePath download_path(download_item->GetTargetFilePath());
140 file_value->Set("file_path", base::CreateFilePathValue(download_path));
141 file_value->SetString("file_url",
142 net::FilePathToFileURL(download_path).spec());
144 extensions::DownloadedByExtension* by_ext =
145 extensions::DownloadedByExtension::Get(download_item);
146 if (by_ext) {
147 file_value->SetString("by_ext_id", by_ext->id());
148 file_value->SetString("by_ext_name", by_ext->name());
149 // Lookup the extension's current name() in case the user changed their
150 // language. This won't work if the extension was uninstalled, so the name
151 // might be the wrong language.
152 bool include_disabled = true;
153 const extensions::Extension* extension = extensions::ExtensionSystem::Get(
154 Profile::FromBrowserContext(download_item->GetBrowserContext()))->
155 extension_service()->GetExtensionById(by_ext->id(), include_disabled);
156 if (extension)
157 file_value->SetString("by_ext_name", extension->name());
160 // Keep file names as LTR.
161 base::string16 file_name =
162 download_item->GetFileNameToReportUser().LossyDisplayName();
163 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
164 file_value->SetString("file_name", file_name);
165 file_value->SetString("url", download_item->GetURL().spec());
166 file_value->SetBoolean("otr", incognito);
167 file_value->SetInteger("total", static_cast<int>(
168 download_item->GetTotalBytes()));
169 file_value->SetBoolean("file_externally_removed",
170 download_item->GetFileExternallyRemoved());
171 file_value->SetBoolean("retry", false); // Overridden below if needed.
172 file_value->SetBoolean("resume", download_item->CanResume());
174 switch (download_item->GetState()) {
175 case content::DownloadItem::IN_PROGRESS:
176 if (download_item->IsDangerous()) {
177 file_value->SetString("state", "DANGEROUS");
178 // These are the only danger states that the UI is equipped to handle.
179 DCHECK(download_item->GetDangerType() ==
180 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
181 download_item->GetDangerType() ==
182 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
183 download_item->GetDangerType() ==
184 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
185 download_item->GetDangerType() ==
186 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
187 download_item->GetDangerType() ==
188 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
189 download_item->GetDangerType() ==
190 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
191 const char* danger_type_value =
192 GetDangerTypeString(download_item->GetDangerType());
193 file_value->SetString("danger_type", danger_type_value);
194 } else if (download_item->IsPaused()) {
195 file_value->SetString("state", "PAUSED");
196 } else {
197 file_value->SetString("state", "IN_PROGRESS");
199 file_value->SetString("progress_status_text",
200 download_model.GetTabProgressStatusText());
202 file_value->SetInteger("percent",
203 std::max(0, static_cast<int>(download_item->PercentComplete())));
204 file_value->SetInteger("received",
205 static_cast<int>(download_item->GetReceivedBytes()));
206 break;
208 case content::DownloadItem::INTERRUPTED:
209 file_value->SetString("state", "INTERRUPTED");
211 file_value->SetString("progress_status_text",
212 download_model.GetTabProgressStatusText());
214 file_value->SetInteger("percent",
215 static_cast<int>(download_item->PercentComplete()));
216 file_value->SetInteger("received",
217 static_cast<int>(download_item->GetReceivedBytes()));
218 file_value->SetString("last_reason_text",
219 download_model.GetInterruptReasonText());
220 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH ==
221 download_item->GetLastReason() && !download_item->CanResume())
222 file_value->SetBoolean("retry", true);
223 break;
225 case content::DownloadItem::CANCELLED:
226 file_value->SetString("state", "CANCELLED");
227 file_value->SetBoolean("retry", true);
228 break;
230 case content::DownloadItem::COMPLETE:
231 DCHECK(!download_item->IsDangerous());
232 file_value->SetString("state", "COMPLETE");
233 break;
235 case content::DownloadItem::MAX_DOWNLOAD_STATE:
236 NOTREACHED();
239 return file_value;
242 // Filters out extension downloads and downloads that don't have a filename yet.
243 bool IsDownloadDisplayable(const content::DownloadItem& item) {
244 return !download_crx_util::IsExtensionDownload(item) &&
245 !item.IsTemporary() &&
246 !item.GetFileNameToReportUser().empty() &&
247 !item.GetTargetFilePath().empty() &&
248 DownloadItemModel(
249 const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf();
252 } // namespace
254 DownloadsDOMHandler::DownloadsDOMHandler(content::DownloadManager* dlm)
255 : main_notifier_(dlm, this),
256 update_scheduled_(false),
257 weak_ptr_factory_(this) {
258 // Create our fileicon data source.
259 Profile* profile = Profile::FromBrowserContext(dlm->GetBrowserContext());
260 content::URLDataSource::Add(profile, new FileIconSource());
262 if (profile->IsOffTheRecord()) {
263 original_notifier_.reset(new AllDownloadItemNotifier(
264 BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
265 this));
269 DownloadsDOMHandler::~DownloadsDOMHandler() {
270 FinalizeRemovals();
273 // DownloadsDOMHandler, public: -----------------------------------------------
275 void DownloadsDOMHandler::RegisterMessages() {
276 web_ui()->RegisterMessageCallback("getDownloads",
277 base::Bind(&DownloadsDOMHandler::HandleGetDownloads,
278 weak_ptr_factory_.GetWeakPtr()));
279 web_ui()->RegisterMessageCallback("openFile",
280 base::Bind(&DownloadsDOMHandler::HandleOpenFile,
281 weak_ptr_factory_.GetWeakPtr()));
282 web_ui()->RegisterMessageCallback("drag",
283 base::Bind(&DownloadsDOMHandler::HandleDrag,
284 weak_ptr_factory_.GetWeakPtr()));
285 web_ui()->RegisterMessageCallback("saveDangerous",
286 base::Bind(&DownloadsDOMHandler::HandleSaveDangerous,
287 weak_ptr_factory_.GetWeakPtr()));
288 web_ui()->RegisterMessageCallback("discardDangerous",
289 base::Bind(&DownloadsDOMHandler::HandleDiscardDangerous,
290 weak_ptr_factory_.GetWeakPtr()));
291 web_ui()->RegisterMessageCallback("show",
292 base::Bind(&DownloadsDOMHandler::HandleShow,
293 weak_ptr_factory_.GetWeakPtr()));
294 web_ui()->RegisterMessageCallback("pause",
295 base::Bind(&DownloadsDOMHandler::HandlePause,
296 weak_ptr_factory_.GetWeakPtr()));
297 web_ui()->RegisterMessageCallback("resume",
298 base::Bind(&DownloadsDOMHandler::HandleResume,
299 weak_ptr_factory_.GetWeakPtr()));
300 web_ui()->RegisterMessageCallback("remove",
301 base::Bind(&DownloadsDOMHandler::HandleRemove,
302 weak_ptr_factory_.GetWeakPtr()));
303 web_ui()->RegisterMessageCallback("undo",
304 base::Bind(&DownloadsDOMHandler::HandleUndo,
305 weak_ptr_factory_.GetWeakPtr()));
306 web_ui()->RegisterMessageCallback("cancel",
307 base::Bind(&DownloadsDOMHandler::HandleCancel,
308 weak_ptr_factory_.GetWeakPtr()));
309 web_ui()->RegisterMessageCallback("clearAll",
310 base::Bind(&DownloadsDOMHandler::HandleClearAll,
311 weak_ptr_factory_.GetWeakPtr()));
312 web_ui()->RegisterMessageCallback("openDownloadsFolder",
313 base::Bind(&DownloadsDOMHandler::HandleOpenDownloadsFolder,
314 weak_ptr_factory_.GetWeakPtr()));
317 void DownloadsDOMHandler::OnDownloadCreated(
318 content::DownloadManager* manager, content::DownloadItem* download_item) {
319 if (IsDownloadDisplayable(*download_item))
320 ScheduleSendCurrentDownloads();
321 else
322 new_downloads_.insert(download_item->GetId());
325 void DownloadsDOMHandler::OnDownloadUpdated(
326 content::DownloadManager* manager,
327 content::DownloadItem* download_item) {
328 bool showing_new_item = false;
330 if (new_downloads_.count(download_item->GetId())) {
331 // A new download (that the page doesn't know about yet) has been updated.
332 if (!IsDownloadDisplayable(*download_item)) {
333 // Item isn't ready to be displayed yet. Wait until it is.
334 return;
337 new_downloads_.erase(download_item->GetId());
338 showing_new_item = true;
341 if (showing_new_item || DownloadItemModel(download_item).IsBeingRevived() ||
342 !IsDownloadDisplayable(*download_item)) {
343 // A download will be shown or hidden by this update. Resend the list.
344 ScheduleSendCurrentDownloads();
345 return;
348 if (search_terms_ && !search_terms_->empty()) {
349 // Don't CallUpdateItem() if download_item doesn't match
350 // search_terms_.
351 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
352 content::DownloadManager::DownloadVector all_items, filtered_items;
353 all_items.push_back(download_item);
354 DownloadQuery query;
355 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
356 query.Search(all_items.begin(), all_items.end(), &filtered_items);
357 if (filtered_items.empty())
358 return;
361 scoped_ptr<base::DictionaryValue> item(CreateDownloadItemValue(
362 download_item,
363 original_notifier_ && manager == main_notifier_.GetManager()));
364 CallUpdateItem(*item);
367 void DownloadsDOMHandler::OnDownloadRemoved(
368 content::DownloadManager* manager,
369 content::DownloadItem* download_item) {
370 if (!DownloadItemModel(download_item).ShouldShowInShelf())
371 return;
373 // This relies on |download_item| being removed from DownloadManager in this
374 // MessageLoop iteration. |download_item| may not have been removed from
375 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
376 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
377 // at all downloads, and we do not tell it that |download_item| is being
378 // removed. If DownloadManager is ever changed to not immediately remove
379 // |download_item| from its map when OnDownloadRemoved is sent, then
380 // DownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
381 // SendCurrentDownloads() that |download_item| was removed. A
382 // SupportsUserData::Data would be the correct way to do this.
383 ScheduleSendCurrentDownloads();
386 void DownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
387 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
388 search_terms_.reset(args && !args->empty() ? args->DeepCopy() : NULL);
389 ScheduleSendCurrentDownloads();
392 void DownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
393 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
394 content::DownloadItem* file = GetDownloadByValue(args);
395 if (file)
396 file->OpenDownload();
399 void DownloadsDOMHandler::HandleDrag(const base::ListValue* args) {
400 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG);
401 content::DownloadItem* file = GetDownloadByValue(args);
402 if (!file)
403 return;
405 content::WebContents* web_contents = GetWebUIWebContents();
406 // |web_contents| is only NULL in the test.
407 if (!web_contents)
408 return;
410 if (file->GetState() != content::DownloadItem::COMPLETE)
411 return;
413 gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
414 file->GetTargetFilePath(), IconLoader::NORMAL);
415 gfx::NativeView view = web_contents->GetNativeView();
417 // Enable nested tasks during DnD, while |DragDownload()| blocks.
418 base::MessageLoop::ScopedNestableTaskAllower allow(
419 base::MessageLoop::current());
420 DragDownloadItem(file, icon, view);
424 void DownloadsDOMHandler::HandleSaveDangerous(const base::ListValue* args) {
425 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
426 content::DownloadItem* file = GetDownloadByValue(args);
427 if (file)
428 ShowDangerPrompt(file);
431 void DownloadsDOMHandler::HandleDiscardDangerous(const base::ListValue* args) {
432 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS);
433 content::DownloadItem* file = GetDownloadByValue(args);
434 if (file)
435 file->Remove();
438 void DownloadsDOMHandler::HandleShow(const base::ListValue* args) {
439 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW);
440 content::DownloadItem* file = GetDownloadByValue(args);
441 if (file)
442 file->ShowDownloadInShell();
445 void DownloadsDOMHandler::HandlePause(const base::ListValue* args) {
446 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE);
447 content::DownloadItem* file = GetDownloadByValue(args);
448 if (file)
449 file->Pause();
452 void DownloadsDOMHandler::HandleResume(const base::ListValue* args) {
453 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_RESUME);
454 content::DownloadItem* file = GetDownloadByValue(args);
455 if (file)
456 file->Resume();
459 void DownloadsDOMHandler::HandleRemove(const base::ListValue* args) {
460 if (!IsDeletingHistoryAllowed())
461 return;
463 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE);
464 content::DownloadItem* file = GetDownloadByValue(args);
465 if (!file)
466 return;
468 std::vector<content::DownloadItem*> downloads;
469 downloads.push_back(file);
470 RemoveDownloads(downloads);
473 void DownloadsDOMHandler::HandleUndo(const base::ListValue* args) {
474 // TODO(dbeam): handle more than removed downloads someday?
475 if (removals_.empty())
476 return;
478 const std::set<uint32> last_removed_ids = removals_.back();
479 removals_.pop_back();
481 for (auto id : last_removed_ids) {
482 content::DownloadItem* download = GetDownloadById(id);
483 if (!download)
484 continue;
486 DownloadItemModel model(download);
487 model.SetShouldShowInShelf(true);
488 model.SetIsBeingRevived(true);
490 download->UpdateObservers();
492 model.SetIsBeingRevived(false);
496 void DownloadsDOMHandler::HandleCancel(const base::ListValue* args) {
497 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL);
498 content::DownloadItem* file = GetDownloadByValue(args);
499 if (file)
500 file->Cancel(true);
503 void DownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
504 if (!IsDeletingHistoryAllowed()) {
505 // This should only be reached during tests.
506 return;
509 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
511 std::vector<content::DownloadItem*> downloads;
512 if (GetMainNotifierManager())
513 GetMainNotifierManager()->GetAllDownloads(&downloads);
514 if (original_notifier_ && original_notifier_->GetManager())
515 original_notifier_->GetManager()->GetAllDownloads(&downloads);
516 RemoveDownloads(downloads);
519 void DownloadsDOMHandler::RemoveDownloads(
520 const std::vector<content::DownloadItem*>& to_remove) {
521 std::set<uint32> ids;
523 for (auto* download : to_remove) {
524 DownloadItemModel item_model(download);
525 if (!item_model.ShouldShowInShelf() ||
526 download->GetState() == content::DownloadItem::IN_PROGRESS) {
527 continue;
530 item_model.SetShouldShowInShelf(false);
531 ids.insert(download->GetId());
532 download->UpdateObservers();
535 if (!ids.empty())
536 removals_.push_back(ids);
539 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
540 const base::ListValue* args) {
541 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER);
542 content::DownloadManager* manager = main_notifier_.GetManager();
543 if (manager) {
544 platform_util::OpenItem(
545 Profile::FromBrowserContext(manager->GetBrowserContext()),
546 DownloadPrefs::FromDownloadManager(manager)->DownloadPath(),
547 platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback());
551 // DownloadsDOMHandler, private: ----------------------------------------------
553 void DownloadsDOMHandler::ScheduleSendCurrentDownloads() {
554 // Don't call SendCurrentDownloads() every time anything changes. Batch them
555 // together instead. This may handle hundreds of OnDownloadDestroyed() calls
556 // in a single UI message loop iteration when the user Clears All downloads.
557 if (update_scheduled_)
558 return;
560 update_scheduled_ = true;
562 BrowserThread::PostTask(
563 BrowserThread::UI, FROM_HERE,
564 base::Bind(&DownloadsDOMHandler::SendCurrentDownloads,
565 weak_ptr_factory_.GetWeakPtr()));
568 content::DownloadManager* DownloadsDOMHandler::GetMainNotifierManager() {
569 return main_notifier_.GetManager();
572 void DownloadsDOMHandler::FinalizeRemovals() {
573 while (!removals_.empty()) {
574 const std::set<uint32> remove = removals_.back();
575 removals_.pop_back();
577 for (const auto id : remove) {
578 content::DownloadItem* download = GetDownloadById(id);
579 if (download)
580 download->Remove();
585 void DownloadsDOMHandler::SendCurrentDownloads() {
586 update_scheduled_ = false;
588 content::DownloadManager::DownloadVector all_items, filtered_items;
589 if (main_notifier_.GetManager()) {
590 main_notifier_.GetManager()->GetAllDownloads(&all_items);
591 main_notifier_.GetManager()->CheckForHistoryFilesRemoval();
593 if (original_notifier_ && original_notifier_->GetManager()) {
594 original_notifier_->GetManager()->GetAllDownloads(&all_items);
595 original_notifier_->GetManager()->CheckForHistoryFilesRemoval();
598 DownloadQuery query;
599 if (search_terms_ && !search_terms_->empty())
600 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
601 query.AddFilter(base::Bind(&IsDownloadDisplayable));
602 query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
603 query.Limit(kMaxDownloads);
604 query.Search(all_items.begin(), all_items.end(), &filtered_items);
606 base::ListValue results_value;
607 for (auto* item : filtered_items) {
608 results_value.Append(CreateDownloadItemValue(
609 item,
610 original_notifier_ && main_notifier_.GetManager() &&
611 main_notifier_.GetManager()->GetDownload(item->GetId()) == item));
613 CallUpdateAll(results_value);
616 void DownloadsDOMHandler::ShowDangerPrompt(
617 content::DownloadItem* dangerous_item) {
618 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
619 dangerous_item,
620 GetWebUIWebContents(),
621 false,
622 base::Bind(&DownloadsDOMHandler::DangerPromptDone,
623 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId()));
624 // danger_prompt will delete itself.
625 DCHECK(danger_prompt);
628 void DownloadsDOMHandler::DangerPromptDone(
629 int download_id, DownloadDangerPrompt::Action action) {
630 if (action != DownloadDangerPrompt::ACCEPT)
631 return;
632 content::DownloadItem* item = NULL;
633 if (main_notifier_.GetManager())
634 item = main_notifier_.GetManager()->GetDownload(download_id);
635 if (!item && original_notifier_.get() && original_notifier_->GetManager())
636 item = original_notifier_->GetManager()->GetDownload(download_id);
637 if (!item || item->IsDone())
638 return;
639 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
640 item->ValidateDangerousDownload();
643 bool DownloadsDOMHandler::IsDeletingHistoryAllowed() {
644 content::DownloadManager* manager = main_notifier_.GetManager();
645 return manager &&
646 Profile::FromBrowserContext(manager->GetBrowserContext())->
647 GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory);
650 content::DownloadItem* DownloadsDOMHandler::GetDownloadByValue(
651 const base::ListValue* args) {
652 std::string download_id;
653 if (!args->GetString(0, &download_id)) {
654 NOTREACHED();
655 return nullptr;
658 uint64 id;
659 if (!base::StringToUint64(download_id, &id)) {
660 NOTREACHED();
661 return nullptr;
664 return GetDownloadById(static_cast<uint32>(id));
667 content::DownloadItem* DownloadsDOMHandler::GetDownloadById(uint32 id) {
668 content::DownloadItem* item = NULL;
669 if (GetMainNotifierManager())
670 item = GetMainNotifierManager()->GetDownload(id);
671 if (!item && original_notifier_ && original_notifier_->GetManager())
672 item = original_notifier_->GetManager()->GetDownload(id);
673 return item;
676 content::WebContents* DownloadsDOMHandler::GetWebUIWebContents() {
677 return web_ui()->GetWebContents();
680 void DownloadsDOMHandler::CallUpdateAll(const base::ListValue& list) {
681 web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list);
684 void DownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue& item) {
685 web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item);