Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3821)

Unified Diff: chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc

Issue 1428833005: MD Downloads: track downloads in C++, dispatch discrete JS updates (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: asdf Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
index 403cbbf3ca063f06b9ae59dbd7a9447482af0352..39d3cc3f462c678aebfff654073563253d9166aa 100644
--- a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
@@ -11,10 +11,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/i18n/rtl.h"
-#include "base/i18n/time_formatting.h"
#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
@@ -22,10 +19,8 @@
#include "base/strings/utf_string_conversions.h"
#include "base/supports_user_data.h"
#include "base/threading/thread.h"
-#include "base/value_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/download_crx_util.h"
#include "chrome/browser/download/download_danger_prompt.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_item_model.h"
@@ -34,8 +29,6 @@
#include "chrome/browser/download/download_service.h"
#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/download/drag_download_item.h"
-#include "chrome/browser/extensions/api/downloads/downloads_api.h"
-#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/fileicon_source.h"
@@ -44,26 +37,20 @@
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_item.h"
+#include "content/public/browser/download_manager.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
-#include "extensions/browser/extension_system.h"
#include "net/base/filename_util.h"
-#include "third_party/icu/source/i18n/unicode/datefmt.h"
#include "ui/base/l10n/time_format.h"
#include "ui/gfx/image/image.h"
using base::UserMetricsAction;
-using content::BrowserContext;
using content::BrowserThread;
namespace {
-// Maximum number of downloads to show. TODO(glen): Remove this and instead
-// stuff the downloads down the pipe slowly.
-size_t kMaxNumberOfDownloads = 150;
-
enum DownloadsDOMEvent {
DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
@@ -86,203 +73,11 @@ void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
DOWNLOADS_DOM_EVENT_MAX);
}
-// Returns a string constant to be used as the |danger_type| value in
-// CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE,
-// DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the
-// |danger_type| value is only defined if the value of |state| is |DANGEROUS|.
-const char* GetDangerTypeString(content::DownloadDangerType danger_type) {
- switch (danger_type) {
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
- return "DANGEROUS_FILE";
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
- return "DANGEROUS_URL";
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
- return "DANGEROUS_CONTENT";
- case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
- return "UNCOMMON_CONTENT";
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
- return "DANGEROUS_HOST";
- case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
- return "POTENTIALLY_UNWANTED";
- default:
- // Don't return a danger type string if it is NOT_DANGEROUS or
- // MAYBE_DANGEROUS_CONTENT.
- NOTREACHED();
- return "";
- }
-}
-
-// TODO(dbeam): if useful elsewhere, move to base/i18n/time_formatting.h?
-base::string16 TimeFormatLongDate(const base::Time& time) {
- scoped_ptr<icu::DateFormat> formatter(
- icu::DateFormat::createDateInstance(icu::DateFormat::kLong));
- icu::UnicodeString date_string;
- formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
- return base::string16(date_string.getBuffer(),
- static_cast<size_t>(date_string.length()));
-}
-
-// Returns a JSON dictionary containing some of the attributes of |download|.
-// The JSON dictionary will also have a field "id" set to |id|, and a field
-// "otr" set to |incognito|.
-base::DictionaryValue* CreateDownloadItemValue(
- content::DownloadItem* download_item,
- bool incognito) {
- // TODO(asanka): Move towards using download_model here for getting status and
- // progress. The difference currently only matters to Drive downloads and
- // those don't show up on the downloads page, but should.
- DownloadItemModel download_model(download_item);
-
- // The items which are to be written into file_value are also described in
- // chrome/browser/resources/downloads/downloads.js in @typedef for
- // BackendDownloadObject. Please update it whenever you add or remove
- // any keys in file_value.
- base::DictionaryValue* file_value = new base::DictionaryValue();
-
- file_value->SetInteger(
- "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
- file_value->SetString(
- "since_string", ui::TimeFormat::RelativeDate(
- download_item->GetStartTime(), NULL));
-
- base::Time start_time = download_item->GetStartTime();
- base::string16 date_string = TimeFormatLongDate(start_time);
- file_value->SetString("date_string", date_string);
-
- file_value->SetString("id", base::Uint64ToString(download_item->GetId()));
-
- base::FilePath download_path(download_item->GetTargetFilePath());
- file_value->Set("file_path", base::CreateFilePathValue(download_path));
- file_value->SetString("file_url",
- net::FilePathToFileURL(download_path).spec());
-
- extensions::DownloadedByExtension* by_ext =
- extensions::DownloadedByExtension::Get(download_item);
- std::string by_ext_id;
- std::string by_ext_name;
- if (by_ext) {
- by_ext_id = by_ext->id();
- // TODO(dbeam): why doesn't DownloadsByExtension::name() return a string16?
- by_ext_name = by_ext->name();
-
- // Lookup the extension's current name() in case the user changed their
- // language. This won't work if the extension was uninstalled, so the name
- // might be the wrong language.
- bool include_disabled = true;
- const extensions::Extension* extension = extensions::ExtensionSystem::Get(
- Profile::FromBrowserContext(download_item->GetBrowserContext()))->
- extension_service()->GetExtensionById(by_ext->id(), include_disabled);
- if (extension)
- file_value->SetString("by_ext_name", extension->name());
- }
- file_value->SetString("by_ext_id", by_ext_id);
- file_value->SetString("by_ext_name", by_ext_name);
-
- // Keep file names as LTR.
- base::string16 file_name =
- download_item->GetFileNameToReportUser().LossyDisplayName();
- file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
- file_value->SetString("file_name", file_name);
- file_value->SetString("url", download_item->GetURL().spec());
- file_value->SetBoolean("otr", incognito);
- file_value->SetInteger("total", static_cast<int>(
- download_item->GetTotalBytes()));
- file_value->SetBoolean("file_externally_removed",
- download_item->GetFileExternallyRemoved());
- file_value->SetBoolean("resume", download_item->CanResume());
-
- const char* danger_type = "";
- base::string16 last_reason_text;
- // -2 is invalid, -1 means indeterminate, and 0-100 are in-progress.
- int percent = -2;
- base::string16 progress_status_text;
- bool retry = false;
- const char* state = nullptr;
-
- switch (download_item->GetState()) {
- case content::DownloadItem::IN_PROGRESS: {
- if (download_item->IsDangerous()) {
- state = "DANGEROUS";
- // These are the only danger states that the UI is equipped to handle.
- DCHECK(download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
- download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
- download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
- download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
- download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
- download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
- danger_type = GetDangerTypeString(download_item->GetDangerType());
- } else if (download_item->IsPaused()) {
- state = "PAUSED";
- } else {
- state = "IN_PROGRESS";
- }
- progress_status_text = download_model.GetTabProgressStatusText();
- percent = download_item->PercentComplete();
- break;
- }
-
- case content::DownloadItem::INTERRUPTED:
- state = "INTERRUPTED";
- progress_status_text = download_model.GetTabProgressStatusText();
-
- if (download_item->CanResume())
- percent = download_item->PercentComplete();
-
- last_reason_text = download_model.GetInterruptReasonText();
- if (content::DOWNLOAD_INTERRUPT_REASON_CRASH ==
- download_item->GetLastReason() && !download_item->CanResume()) {
- retry = true;
- }
- break;
-
- case content::DownloadItem::CANCELLED:
- state = "CANCELLED";
- retry = true;
- break;
-
- case content::DownloadItem::COMPLETE:
- DCHECK(!download_item->IsDangerous());
- state = "COMPLETE";
- break;
-
- case content::DownloadItem::MAX_DOWNLOAD_STATE:
- NOTREACHED();
- }
-
- DCHECK(state);
-
- file_value->SetString("danger_type", danger_type);
- file_value->SetString("last_reason_text", last_reason_text);
- file_value->SetInteger("percent", percent);
- file_value->SetString("progress_status_text", progress_status_text);
- file_value->SetBoolean("retry", retry);
- file_value->SetString("state", state);
-
- return file_value;
-}
-
-// Filters out extension downloads and downloads that don't have a filename yet.
-bool IsDownloadDisplayable(const content::DownloadItem& item) {
- return !download_crx_util::IsExtensionDownload(item) &&
- !item.IsTemporary() &&
- !item.GetFileNameToReportUser().empty() &&
- !item.GetTargetFilePath().empty() &&
- DownloadItemModel(
- const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf();
-}
-
} // namespace
MdDownloadsDOMHandler::MdDownloadsDOMHandler(
- content::DownloadManager* download_manager)
- : download_manager_(download_manager),
- update_scheduled_(false),
+ content::DownloadManager* download_manager, content::WebUI* web_ui)
+ : list_tracker_(download_manager, web_ui),
weak_ptr_factory_(this) {
// Create our fileicon data source.
Profile* profile = Profile::FromBrowserContext(
@@ -338,95 +133,19 @@ void MdDownloadsDOMHandler::RegisterMessages() {
weak_ptr_factory_.GetWeakPtr()));
}
-void MdDownloadsDOMHandler::OnDownloadCreated(
- content::DownloadManager* manager, content::DownloadItem* download_item) {
- if (IsDownloadDisplayable(*download_item))
- ScheduleSendCurrentDownloads();
- else
- new_downloads_.insert(download_item->GetId());
-}
-
-void MdDownloadsDOMHandler::OnDownloadUpdated(
- content::DownloadManager* manager,
- content::DownloadItem* download_item) {
- if (update_scheduled_)
- return;
-
- bool showing_new_item = false;
-
- if (new_downloads_.count(download_item->GetId())) {
- // A new download (that the page doesn't know about yet) has been updated.
- if (!IsDownloadDisplayable(*download_item)) {
- // Item isn't ready to be displayed yet. Wait until it is.
- return;
- }
-
- new_downloads_.erase(download_item->GetId());
- showing_new_item = true;
- }
-
- if (showing_new_item || DownloadItemModel(download_item).IsBeingRevived() ||
- !IsDownloadDisplayable(*download_item)) {
- // A download will be shown or hidden by this update. Resend the list.
- ScheduleSendCurrentDownloads();
- return;
- }
-
- if (search_terms_ && !search_terms_->empty()) {
- // Don't CallUpdateItem() if download_item doesn't match
- // search_terms_.
- // TODO(benjhayden): Consider splitting MatchesQuery() out to a function.
- content::DownloadManager::DownloadVector all_items, filtered_items;
- all_items.push_back(download_item);
- DownloadQuery query;
- query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
- query.Search(all_items.begin(), all_items.end(), &filtered_items);
- if (filtered_items.empty())
- return;
- }
-
- DCHECK(manager);
- scoped_ptr<base::DictionaryValue> item(CreateDownloadItemValue(
- download_item,
- original_notifier_ && manager == GetMainNotifierManager()));
- CallUpdateItem(*item);
-}
-
-void MdDownloadsDOMHandler::OnDownloadRemoved(
- content::DownloadManager* manager,
- content::DownloadItem* download_item) {
- if (!DownloadItemModel(download_item).ShouldShowInShelf())
- return;
-
- // This relies on |download_item| being removed from DownloadManager in this
- // MessageLoop iteration. |download_item| may not have been removed from
- // DownloadManager when OnDownloadRemoved() is fired, so bounce off the
- // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks
- // at all downloads, and we do not tell it that |download_item| is being
- // removed. If DownloadManager is ever changed to not immediately remove
- // |download_item| from its map when OnDownloadRemoved is sent, then
- // MdDownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell
- // SendCurrentDownloads() that |download_item| was removed. A
- // SupportsUserData::Data would be the correct way to do this.
- ScheduleSendCurrentDownloads();
+void MdDownloadsDOMHandler::RenderViewReused(
+ content::RenderViewHost* render_view_host) {
+ list_tracker_.Stop();
}
void MdDownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) {
CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
- search_terms_.reset(args && !args->empty() ? args->DeepCopy() : NULL);
- ScheduleSendCurrentDownloads();
-
- if (!main_notifier_) {
- main_notifier_.reset(new AllDownloadItemNotifier(download_manager_, this));
-
- Profile* profile = Profile::FromBrowserContext(
- download_manager_->GetBrowserContext());
- if (profile->IsOffTheRecord()) {
- original_notifier_.reset(new AllDownloadItemNotifier(
- BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
- this));
- }
- }
+
+ bool terms_changed = list_tracker_.SetSearchTerms(*args);
+ if (terms_changed)
+ list_tracker_.CallClearAll();
+
+ list_tracker_.Start();
}
void MdDownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) {
@@ -549,12 +268,17 @@ void MdDownloadsDOMHandler::HandleClearAll(const base::ListValue* args) {
CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
+ list_tracker_.CallClearAll();
+ list_tracker_.Stop();
+
DownloadVector downloads;
if (GetMainNotifierManager())
GetMainNotifierManager()->GetAllDownloads(&downloads);
if (GetOriginalNotifierManager())
GetOriginalNotifierManager()->GetAllDownloads(&downloads);
RemoveDownloads(downloads);
+
+ list_tracker_.Start();
}
void MdDownloadsDOMHandler::RemoveDownloads(const DownloadVector& to_remove) {
@@ -590,29 +314,14 @@ void MdDownloadsDOMHandler::HandleOpenDownloadsFolder(
// MdDownloadsDOMHandler, private: --------------------------------------------
-void MdDownloadsDOMHandler::ScheduleSendCurrentDownloads() {
- // Don't call SendCurrentDownloads() every time anything changes. Batch them
- // together instead. This may handle hundreds of OnDownloadDestroyed() calls
- // in a single UI message loop iteration when the user Clears All downloads.
- if (update_scheduled_)
- return;
-
- update_scheduled_ = true;
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&MdDownloadsDOMHandler::SendCurrentDownloads,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
content::DownloadManager* MdDownloadsDOMHandler::GetMainNotifierManager()
const {
- return main_notifier_ ? main_notifier_->GetManager() : nullptr;
+ return list_tracker_.GetMainNotifierManager();
}
content::DownloadManager* MdDownloadsDOMHandler::GetOriginalNotifierManager()
const {
- return original_notifier_ ? original_notifier_->GetManager() : nullptr;
+ return list_tracker_.GetOriginalNotifierManager();
}
void MdDownloadsDOMHandler::FinalizeRemovals() {
@@ -628,37 +337,6 @@ void MdDownloadsDOMHandler::FinalizeRemovals() {
}
}
-void MdDownloadsDOMHandler::SendCurrentDownloads() {
- update_scheduled_ = false;
-
- content::DownloadManager::DownloadVector all_items, filtered_items;
- if (GetMainNotifierManager()) {
- GetMainNotifierManager()->GetAllDownloads(&all_items);
- GetMainNotifierManager()->CheckForHistoryFilesRemoval();
- }
- if (GetOriginalNotifierManager()) {
- GetOriginalNotifierManager()->GetAllDownloads(&all_items);
- GetOriginalNotifierManager()->CheckForHistoryFilesRemoval();
- }
-
- DownloadQuery query;
- if (search_terms_ && !search_terms_->empty())
- query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_);
- query.AddFilter(base::Bind(&IsDownloadDisplayable));
- query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
- query.Limit(kMaxNumberOfDownloads);
- query.Search(all_items.begin(), all_items.end(), &filtered_items);
-
- base::ListValue results_value;
- for (auto* item : filtered_items) {
- results_value.Append(CreateDownloadItemValue(
- item,
- original_notifier_ && GetMainNotifierManager() &&
- GetMainNotifierManager()->GetDownload(item->GetId()) == item));
- }
- CallUpdateAll(results_value);
-}
-
void MdDownloadsDOMHandler::ShowDangerPrompt(
content::DownloadItem* dangerous_item) {
DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create(
@@ -722,11 +400,3 @@ content::DownloadItem* MdDownloadsDOMHandler::GetDownloadById(uint32 id) {
content::WebContents* MdDownloadsDOMHandler::GetWebUIWebContents() {
return web_ui()->GetWebContents();
}
-
-void MdDownloadsDOMHandler::CallUpdateAll(const base::ListValue& list) {
- web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list);
-}
-
-void MdDownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue& item) {
- web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item);
-}

Powered by Google App Engine
This is Rietveld 408576698