Chromium Code Reviews| 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(); |
|
Dan Beam
2016/01/21 02:21:42
^ well, I dropped this on the floor
|
| - } |
| - 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); |
| -} |