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