OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h" | 5 #include "chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/i18n/rtl.h" | 13 #include "base/i18n/rtl.h" |
14 #include "base/i18n/time_formatting.h" | |
15 #include "base/logging.h" | 14 #include "base/logging.h" |
16 #include "base/memory/singleton.h" | |
17 #include "base/metrics/field_trial.h" | |
18 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
19 #include "base/prefs/pref_service.h" | 16 #include "base/prefs/pref_service.h" |
20 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
21 #include "base/strings/string_piece.h" | 18 #include "base/strings/string_piece.h" |
22 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
23 #include "base/supports_user_data.h" | 20 #include "base/supports_user_data.h" |
24 #include "base/threading/thread.h" | 21 #include "base/threading/thread.h" |
25 #include "base/value_conversions.h" | |
26 #include "base/values.h" | 22 #include "base/values.h" |
27 #include "chrome/browser/browser_process.h" | 23 #include "chrome/browser/browser_process.h" |
28 #include "chrome/browser/download/download_crx_util.h" | |
29 #include "chrome/browser/download/download_danger_prompt.h" | 24 #include "chrome/browser/download/download_danger_prompt.h" |
30 #include "chrome/browser/download/download_history.h" | 25 #include "chrome/browser/download/download_history.h" |
31 #include "chrome/browser/download/download_item_model.h" | 26 #include "chrome/browser/download/download_item_model.h" |
32 #include "chrome/browser/download/download_prefs.h" | 27 #include "chrome/browser/download/download_prefs.h" |
33 #include "chrome/browser/download/download_query.h" | 28 #include "chrome/browser/download/download_query.h" |
34 #include "chrome/browser/download/download_service.h" | 29 #include "chrome/browser/download/download_service.h" |
35 #include "chrome/browser/download/download_service_factory.h" | 30 #include "chrome/browser/download/download_service_factory.h" |
36 #include "chrome/browser/download/drag_download_item.h" | 31 #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" | 32 #include "chrome/browser/platform_util.h" |
40 #include "chrome/browser/profiles/profile.h" | 33 #include "chrome/browser/profiles/profile.h" |
41 #include "chrome/browser/ui/webui/fileicon_source.h" | 34 #include "chrome/browser/ui/webui/fileicon_source.h" |
42 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" |
43 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
44 #include "chrome/common/url_constants.h" | 37 #include "chrome/common/url_constants.h" |
45 #include "content/public/browser/browser_thread.h" | 38 #include "content/public/browser/browser_thread.h" |
46 #include "content/public/browser/download_item.h" | 39 #include "content/public/browser/download_item.h" |
40 #include "content/public/browser/download_manager.h" | |
47 #include "content/public/browser/url_data_source.h" | 41 #include "content/public/browser/url_data_source.h" |
48 #include "content/public/browser/user_metrics.h" | 42 #include "content/public/browser/user_metrics.h" |
49 #include "content/public/browser/web_contents.h" | 43 #include "content/public/browser/web_contents.h" |
50 #include "content/public/browser/web_ui.h" | 44 #include "content/public/browser/web_ui.h" |
51 #include "extensions/browser/extension_system.h" | |
52 #include "net/base/filename_util.h" | 45 #include "net/base/filename_util.h" |
53 #include "third_party/icu/source/i18n/unicode/datefmt.h" | |
54 #include "ui/base/l10n/time_format.h" | 46 #include "ui/base/l10n/time_format.h" |
55 #include "ui/gfx/image/image.h" | 47 #include "ui/gfx/image/image.h" |
56 | 48 |
57 using base::UserMetricsAction; | 49 using base::UserMetricsAction; |
58 using content::BrowserContext; | |
59 using content::BrowserThread; | 50 using content::BrowserThread; |
60 | 51 |
61 namespace { | 52 namespace { |
62 | 53 |
63 // Maximum number of downloads to show. TODO(glen): Remove this and instead | |
64 // stuff the downloads down the pipe slowly. | |
65 size_t kMaxNumberOfDownloads = 150; | |
66 | |
67 enum DownloadsDOMEvent { | 54 enum DownloadsDOMEvent { |
68 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0, | 55 DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0, |
69 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1, | 56 DOWNLOADS_DOM_EVENT_OPEN_FILE = 1, |
70 DOWNLOADS_DOM_EVENT_DRAG = 2, | 57 DOWNLOADS_DOM_EVENT_DRAG = 2, |
71 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3, | 58 DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3, |
72 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4, | 59 DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4, |
73 DOWNLOADS_DOM_EVENT_SHOW = 5, | 60 DOWNLOADS_DOM_EVENT_SHOW = 5, |
74 DOWNLOADS_DOM_EVENT_PAUSE = 6, | 61 DOWNLOADS_DOM_EVENT_PAUSE = 6, |
75 DOWNLOADS_DOM_EVENT_REMOVE = 7, | 62 DOWNLOADS_DOM_EVENT_REMOVE = 7, |
76 DOWNLOADS_DOM_EVENT_CANCEL = 8, | 63 DOWNLOADS_DOM_EVENT_CANCEL = 8, |
77 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9, | 64 DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9, |
78 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10, | 65 DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10, |
79 DOWNLOADS_DOM_EVENT_RESUME = 11, | 66 DOWNLOADS_DOM_EVENT_RESUME = 11, |
80 DOWNLOADS_DOM_EVENT_MAX | 67 DOWNLOADS_DOM_EVENT_MAX |
81 }; | 68 }; |
82 | 69 |
83 void CountDownloadsDOMEvents(DownloadsDOMEvent event) { | 70 void CountDownloadsDOMEvents(DownloadsDOMEvent event) { |
84 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", | 71 UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent", |
85 event, | 72 event, |
86 DOWNLOADS_DOM_EVENT_MAX); | 73 DOWNLOADS_DOM_EVENT_MAX); |
87 } | 74 } |
88 | 75 |
89 // Returns a string constant to be used as the |danger_type| value in | |
90 // CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE, | |
91 // DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the | |
92 // |danger_type| value is only defined if the value of |state| is |DANGEROUS|. | |
93 const char* GetDangerTypeString(content::DownloadDangerType danger_type) { | |
94 switch (danger_type) { | |
95 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: | |
96 return "DANGEROUS_FILE"; | |
97 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: | |
98 return "DANGEROUS_URL"; | |
99 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: | |
100 return "DANGEROUS_CONTENT"; | |
101 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: | |
102 return "UNCOMMON_CONTENT"; | |
103 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: | |
104 return "DANGEROUS_HOST"; | |
105 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: | |
106 return "POTENTIALLY_UNWANTED"; | |
107 default: | |
108 // Don't return a danger type string if it is NOT_DANGEROUS or | |
109 // MAYBE_DANGEROUS_CONTENT. | |
110 NOTREACHED(); | |
111 return ""; | |
112 } | |
113 } | |
114 | |
115 // TODO(dbeam): if useful elsewhere, move to base/i18n/time_formatting.h? | |
116 base::string16 TimeFormatLongDate(const base::Time& time) { | |
117 scoped_ptr<icu::DateFormat> formatter( | |
118 icu::DateFormat::createDateInstance(icu::DateFormat::kLong)); | |
119 icu::UnicodeString date_string; | |
120 formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string); | |
121 return base::string16(date_string.getBuffer(), | |
122 static_cast<size_t>(date_string.length())); | |
123 } | |
124 | |
125 // Returns a JSON dictionary containing some of the attributes of |download|. | |
126 // The JSON dictionary will also have a field "id" set to |id|, and a field | |
127 // "otr" set to |incognito|. | |
128 base::DictionaryValue* CreateDownloadItemValue( | |
129 content::DownloadItem* download_item, | |
130 bool incognito) { | |
131 // TODO(asanka): Move towards using download_model here for getting status and | |
132 // progress. The difference currently only matters to Drive downloads and | |
133 // those don't show up on the downloads page, but should. | |
134 DownloadItemModel download_model(download_item); | |
135 | |
136 // The items which are to be written into file_value are also described in | |
137 // chrome/browser/resources/downloads/downloads.js in @typedef for | |
138 // BackendDownloadObject. Please update it whenever you add or remove | |
139 // any keys in file_value. | |
140 base::DictionaryValue* file_value = new base::DictionaryValue(); | |
141 | |
142 file_value->SetInteger( | |
143 "started", static_cast<int>(download_item->GetStartTime().ToTimeT())); | |
144 file_value->SetString( | |
145 "since_string", ui::TimeFormat::RelativeDate( | |
146 download_item->GetStartTime(), NULL)); | |
147 | |
148 base::Time start_time = download_item->GetStartTime(); | |
149 base::string16 date_string = TimeFormatLongDate(start_time); | |
150 file_value->SetString("date_string", date_string); | |
151 | |
152 file_value->SetString("id", base::Uint64ToString(download_item->GetId())); | |
153 | |
154 base::FilePath download_path(download_item->GetTargetFilePath()); | |
155 file_value->Set("file_path", base::CreateFilePathValue(download_path)); | |
156 file_value->SetString("file_url", | |
157 net::FilePathToFileURL(download_path).spec()); | |
158 | |
159 extensions::DownloadedByExtension* by_ext = | |
160 extensions::DownloadedByExtension::Get(download_item); | |
161 std::string by_ext_id; | |
162 std::string by_ext_name; | |
163 if (by_ext) { | |
164 by_ext_id = by_ext->id(); | |
165 // TODO(dbeam): why doesn't DownloadsByExtension::name() return a string16? | |
166 by_ext_name = by_ext->name(); | |
167 | |
168 // Lookup the extension's current name() in case the user changed their | |
169 // language. This won't work if the extension was uninstalled, so the name | |
170 // might be the wrong language. | |
171 bool include_disabled = true; | |
172 const extensions::Extension* extension = extensions::ExtensionSystem::Get( | |
173 Profile::FromBrowserContext(download_item->GetBrowserContext()))-> | |
174 extension_service()->GetExtensionById(by_ext->id(), include_disabled); | |
175 if (extension) | |
176 file_value->SetString("by_ext_name", extension->name()); | |
177 } | |
178 file_value->SetString("by_ext_id", by_ext_id); | |
179 file_value->SetString("by_ext_name", by_ext_name); | |
180 | |
181 // Keep file names as LTR. | |
182 base::string16 file_name = | |
183 download_item->GetFileNameToReportUser().LossyDisplayName(); | |
184 file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name); | |
185 file_value->SetString("file_name", file_name); | |
186 file_value->SetString("url", download_item->GetURL().spec()); | |
187 file_value->SetBoolean("otr", incognito); | |
188 file_value->SetInteger("total", static_cast<int>( | |
189 download_item->GetTotalBytes())); | |
190 file_value->SetBoolean("file_externally_removed", | |
191 download_item->GetFileExternallyRemoved()); | |
192 file_value->SetBoolean("resume", download_item->CanResume()); | |
193 | |
194 const char* danger_type = ""; | |
195 base::string16 last_reason_text; | |
196 // -2 is invalid, -1 means indeterminate, and 0-100 are in-progress. | |
197 int percent = -2; | |
198 base::string16 progress_status_text; | |
199 bool retry = false; | |
200 const char* state = nullptr; | |
201 | |
202 switch (download_item->GetState()) { | |
203 case content::DownloadItem::IN_PROGRESS: { | |
204 if (download_item->IsDangerous()) { | |
205 state = "DANGEROUS"; | |
206 // These are the only danger states that the UI is equipped to handle. | |
207 DCHECK(download_item->GetDangerType() == | |
208 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE || | |
209 download_item->GetDangerType() == | |
210 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL || | |
211 download_item->GetDangerType() == | |
212 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT || | |
213 download_item->GetDangerType() == | |
214 content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT || | |
215 download_item->GetDangerType() == | |
216 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST || | |
217 download_item->GetDangerType() == | |
218 content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED); | |
219 danger_type = GetDangerTypeString(download_item->GetDangerType()); | |
220 } else if (download_item->IsPaused()) { | |
221 state = "PAUSED"; | |
222 } else { | |
223 state = "IN_PROGRESS"; | |
224 } | |
225 progress_status_text = download_model.GetTabProgressStatusText(); | |
226 percent = download_item->PercentComplete(); | |
227 break; | |
228 } | |
229 | |
230 case content::DownloadItem::INTERRUPTED: | |
231 state = "INTERRUPTED"; | |
232 progress_status_text = download_model.GetTabProgressStatusText(); | |
233 | |
234 if (download_item->CanResume()) | |
235 percent = download_item->PercentComplete(); | |
236 | |
237 last_reason_text = download_model.GetInterruptReasonText(); | |
238 if (content::DOWNLOAD_INTERRUPT_REASON_CRASH == | |
239 download_item->GetLastReason() && !download_item->CanResume()) { | |
240 retry = true; | |
241 } | |
242 break; | |
243 | |
244 case content::DownloadItem::CANCELLED: | |
245 state = "CANCELLED"; | |
246 retry = true; | |
247 break; | |
248 | |
249 case content::DownloadItem::COMPLETE: | |
250 DCHECK(!download_item->IsDangerous()); | |
251 state = "COMPLETE"; | |
252 break; | |
253 | |
254 case content::DownloadItem::MAX_DOWNLOAD_STATE: | |
255 NOTREACHED(); | |
256 } | |
257 | |
258 DCHECK(state); | |
259 | |
260 file_value->SetString("danger_type", danger_type); | |
261 file_value->SetString("last_reason_text", last_reason_text); | |
262 file_value->SetInteger("percent", percent); | |
263 file_value->SetString("progress_status_text", progress_status_text); | |
264 file_value->SetBoolean("retry", retry); | |
265 file_value->SetString("state", state); | |
266 | |
267 return file_value; | |
268 } | |
269 | |
270 // Filters out extension downloads and downloads that don't have a filename yet. | |
271 bool IsDownloadDisplayable(const content::DownloadItem& item) { | |
272 return !download_crx_util::IsExtensionDownload(item) && | |
273 !item.IsTemporary() && | |
274 !item.GetFileNameToReportUser().empty() && | |
275 !item.GetTargetFilePath().empty() && | |
276 DownloadItemModel( | |
277 const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf(); | |
278 } | |
279 | |
280 } // namespace | 76 } // namespace |
281 | 77 |
282 MdDownloadsDOMHandler::MdDownloadsDOMHandler( | 78 MdDownloadsDOMHandler::MdDownloadsDOMHandler( |
283 content::DownloadManager* download_manager) | 79 content::DownloadManager* download_manager, content::WebUI* web_ui) |
284 : download_manager_(download_manager), | 80 : list_tracker_(download_manager, web_ui), |
285 update_scheduled_(false), | |
286 weak_ptr_factory_(this) { | 81 weak_ptr_factory_(this) { |
287 // Create our fileicon data source. | 82 // Create our fileicon data source. |
288 Profile* profile = Profile::FromBrowserContext( | 83 Profile* profile = Profile::FromBrowserContext( |
289 download_manager->GetBrowserContext()); | 84 download_manager->GetBrowserContext()); |
290 content::URLDataSource::Add(profile, new FileIconSource()); | 85 content::URLDataSource::Add(profile, new FileIconSource()); |
291 } | 86 } |
292 | 87 |
293 MdDownloadsDOMHandler::~MdDownloadsDOMHandler() { | 88 MdDownloadsDOMHandler::~MdDownloadsDOMHandler() { |
294 FinalizeRemovals(); | 89 FinalizeRemovals(); |
295 } | 90 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
331 base::Bind(&MdDownloadsDOMHandler::HandleCancel, | 126 base::Bind(&MdDownloadsDOMHandler::HandleCancel, |
332 weak_ptr_factory_.GetWeakPtr())); | 127 weak_ptr_factory_.GetWeakPtr())); |
333 web_ui()->RegisterMessageCallback("clearAll", | 128 web_ui()->RegisterMessageCallback("clearAll", |
334 base::Bind(&MdDownloadsDOMHandler::HandleClearAll, | 129 base::Bind(&MdDownloadsDOMHandler::HandleClearAll, |
335 weak_ptr_factory_.GetWeakPtr())); | 130 weak_ptr_factory_.GetWeakPtr())); |
336 web_ui()->RegisterMessageCallback("openDownloadsFolder", | 131 web_ui()->RegisterMessageCallback("openDownloadsFolder", |
337 base::Bind(&MdDownloadsDOMHandler::HandleOpenDownloadsFolder, | 132 base::Bind(&MdDownloadsDOMHandler::HandleOpenDownloadsFolder, |
338 weak_ptr_factory_.GetWeakPtr())); | 133 weak_ptr_factory_.GetWeakPtr())); |
339 } | 134 } |
340 | 135 |
341 void MdDownloadsDOMHandler::OnDownloadCreated( | 136 void MdDownloadsDOMHandler::RenderViewReused( |
342 content::DownloadManager* manager, content::DownloadItem* download_item) { | 137 content::RenderViewHost* render_view_host) { |
343 if (IsDownloadDisplayable(*download_item)) | 138 list_tracker_.Stop(); |
344 ScheduleSendCurrentDownloads(); | |
345 else | |
346 new_downloads_.insert(download_item->GetId()); | |
347 } | |
348 | |
349 void MdDownloadsDOMHandler::OnDownloadUpdated( | |
350 content::DownloadManager* manager, | |
351 content::DownloadItem* download_item) { | |
352 if (update_scheduled_) | |
353 return; | |
354 | |
355 bool showing_new_item = false; | |
356 | |
357 if (new_downloads_.count(download_item->GetId())) { | |
358 // A new download (that the page doesn't know about yet) has been updated. | |
359 if (!IsDownloadDisplayable(*download_item)) { | |
360 // Item isn't ready to be displayed yet. Wait until it is. | |
361 return; | |
362 } | |
363 | |
364 new_downloads_.erase(download_item->GetId()); | |
365 showing_new_item = true; | |
366 } | |
367 | |
368 if (showing_new_item || DownloadItemModel(download_item).IsBeingRevived() || | |
369 !IsDownloadDisplayable(*download_item)) { | |
370 // A download will be shown or hidden by this update. Resend the list. | |
371 ScheduleSendCurrentDownloads(); | |
372 return; | |
373 } | |
374 | |
375 if (search_terms_ && !search_terms_->empty()) { | |
376 // Don't CallUpdateItem() if download_item doesn't match | |
377 // search_terms_. | |
378 // TODO(benjhayden): Consider splitting MatchesQuery() out to a function. | |
379 content::DownloadManager::DownloadVector all_items, filtered_items; | |
380 all_items.push_back(download_item); | |
381 DownloadQuery query; | |
382 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_); | |
383 query.Search(all_items.begin(), all_items.end(), &filtered_items); | |
384 if (filtered_items.empty()) | |
385 return; | |
386 } | |
387 | |
388 DCHECK(manager); | |
389 scoped_ptr<base::DictionaryValue> item(CreateDownloadItemValue( | |
390 download_item, | |
391 original_notifier_ && manager == GetMainNotifierManager())); | |
392 CallUpdateItem(*item); | |
393 } | |
394 | |
395 void MdDownloadsDOMHandler::OnDownloadRemoved( | |
396 content::DownloadManager* manager, | |
397 content::DownloadItem* download_item) { | |
398 if (!DownloadItemModel(download_item).ShouldShowInShelf()) | |
399 return; | |
400 | |
401 // This relies on |download_item| being removed from DownloadManager in this | |
402 // MessageLoop iteration. |download_item| may not have been removed from | |
403 // DownloadManager when OnDownloadRemoved() is fired, so bounce off the | |
404 // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks | |
405 // at all downloads, and we do not tell it that |download_item| is being | |
406 // removed. If DownloadManager is ever changed to not immediately remove | |
407 // |download_item| from its map when OnDownloadRemoved is sent, then | |
408 // MdDownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell | |
409 // SendCurrentDownloads() that |download_item| was removed. A | |
410 // SupportsUserData::Data would be the correct way to do this. | |
411 ScheduleSendCurrentDownloads(); | |
412 } | 139 } |
413 | 140 |
414 void MdDownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) { | 141 void MdDownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) { |
415 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS); | 142 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS); |
416 search_terms_.reset(args && !args->empty() ? args->DeepCopy() : NULL); | |
417 ScheduleSendCurrentDownloads(); | |
418 | 143 |
419 if (!main_notifier_) { | 144 bool terms_changed = list_tracker_.SetSearchTerms(*args); |
420 main_notifier_.reset(new AllDownloadItemNotifier(download_manager_, this)); | 145 if (terms_changed) |
146 list_tracker_.CallClearAll(); | |
421 | 147 |
422 Profile* profile = Profile::FromBrowserContext( | 148 list_tracker_.Start(); |
423 download_manager_->GetBrowserContext()); | |
424 if (profile->IsOffTheRecord()) { | |
425 original_notifier_.reset(new AllDownloadItemNotifier( | |
426 BrowserContext::GetDownloadManager(profile->GetOriginalProfile()), | |
427 this)); | |
428 } | |
429 } | |
430 } | 149 } |
431 | 150 |
432 void MdDownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) { | 151 void MdDownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) { |
433 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE); | 152 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE); |
434 content::DownloadItem* file = GetDownloadByValue(args); | 153 content::DownloadItem* file = GetDownloadByValue(args); |
435 if (file) | 154 if (file) |
436 file->OpenDownload(); | 155 file->OpenDownload(); |
437 } | 156 } |
438 | 157 |
439 void MdDownloadsDOMHandler::HandleDrag(const base::ListValue* args) { | 158 void MdDownloadsDOMHandler::HandleDrag(const base::ListValue* args) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
542 } | 261 } |
543 | 262 |
544 void MdDownloadsDOMHandler::HandleClearAll(const base::ListValue* args) { | 263 void MdDownloadsDOMHandler::HandleClearAll(const base::ListValue* args) { |
545 if (!IsDeletingHistoryAllowed()) { | 264 if (!IsDeletingHistoryAllowed()) { |
546 // This should only be reached during tests. | 265 // This should only be reached during tests. |
547 return; | 266 return; |
548 } | 267 } |
549 | 268 |
550 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL); | 269 CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL); |
551 | 270 |
271 list_tracker_.CallClearAll(); | |
272 list_tracker_.Stop(); | |
273 | |
552 DownloadVector downloads; | 274 DownloadVector downloads; |
553 if (GetMainNotifierManager()) | 275 if (GetMainNotifierManager()) |
554 GetMainNotifierManager()->GetAllDownloads(&downloads); | 276 GetMainNotifierManager()->GetAllDownloads(&downloads); |
555 if (GetOriginalNotifierManager()) | 277 if (GetOriginalNotifierManager()) |
556 GetOriginalNotifierManager()->GetAllDownloads(&downloads); | 278 GetOriginalNotifierManager()->GetAllDownloads(&downloads); |
557 RemoveDownloads(downloads); | 279 RemoveDownloads(downloads); |
280 | |
281 list_tracker_.Start(); | |
558 } | 282 } |
559 | 283 |
560 void MdDownloadsDOMHandler::RemoveDownloads(const DownloadVector& to_remove) { | 284 void MdDownloadsDOMHandler::RemoveDownloads(const DownloadVector& to_remove) { |
561 IdSet ids; | 285 IdSet ids; |
562 | 286 |
563 for (auto* download : to_remove) { | 287 for (auto* download : to_remove) { |
564 DownloadItemModel item_model(download); | 288 DownloadItemModel item_model(download); |
565 if (!item_model.ShouldShowInShelf() || | 289 if (!item_model.ShouldShowInShelf() || |
566 download->GetState() == content::DownloadItem::IN_PROGRESS) { | 290 download->GetState() == content::DownloadItem::IN_PROGRESS) { |
567 continue; | 291 continue; |
(...skipping 15 matching lines...) Expand all Loading... | |
583 if (manager) { | 307 if (manager) { |
584 platform_util::OpenItem( | 308 platform_util::OpenItem( |
585 Profile::FromBrowserContext(manager->GetBrowserContext()), | 309 Profile::FromBrowserContext(manager->GetBrowserContext()), |
586 DownloadPrefs::FromDownloadManager(manager)->DownloadPath(), | 310 DownloadPrefs::FromDownloadManager(manager)->DownloadPath(), |
587 platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback()); | 311 platform_util::OPEN_FOLDER, platform_util::OpenOperationCallback()); |
588 } | 312 } |
589 } | 313 } |
590 | 314 |
591 // MdDownloadsDOMHandler, private: -------------------------------------------- | 315 // MdDownloadsDOMHandler, private: -------------------------------------------- |
592 | 316 |
593 void MdDownloadsDOMHandler::ScheduleSendCurrentDownloads() { | |
594 // Don't call SendCurrentDownloads() every time anything changes. Batch them | |
595 // together instead. This may handle hundreds of OnDownloadDestroyed() calls | |
596 // in a single UI message loop iteration when the user Clears All downloads. | |
597 if (update_scheduled_) | |
598 return; | |
599 | |
600 update_scheduled_ = true; | |
601 | |
602 BrowserThread::PostTask( | |
603 BrowserThread::UI, FROM_HERE, | |
604 base::Bind(&MdDownloadsDOMHandler::SendCurrentDownloads, | |
605 weak_ptr_factory_.GetWeakPtr())); | |
606 } | |
607 | |
608 content::DownloadManager* MdDownloadsDOMHandler::GetMainNotifierManager() | 317 content::DownloadManager* MdDownloadsDOMHandler::GetMainNotifierManager() |
609 const { | 318 const { |
610 return main_notifier_ ? main_notifier_->GetManager() : nullptr; | 319 return list_tracker_.GetMainNotifierManager(); |
611 } | 320 } |
612 | 321 |
613 content::DownloadManager* MdDownloadsDOMHandler::GetOriginalNotifierManager() | 322 content::DownloadManager* MdDownloadsDOMHandler::GetOriginalNotifierManager() |
614 const { | 323 const { |
615 return original_notifier_ ? original_notifier_->GetManager() : nullptr; | 324 return list_tracker_.GetOriginalNotifierManager(); |
616 } | 325 } |
617 | 326 |
618 void MdDownloadsDOMHandler::FinalizeRemovals() { | 327 void MdDownloadsDOMHandler::FinalizeRemovals() { |
619 while (!removals_.empty()) { | 328 while (!removals_.empty()) { |
620 const IdSet remove = removals_.back(); | 329 const IdSet remove = removals_.back(); |
621 removals_.pop_back(); | 330 removals_.pop_back(); |
622 | 331 |
623 for (const auto id : remove) { | 332 for (const auto id : remove) { |
624 content::DownloadItem* download = GetDownloadById(id); | 333 content::DownloadItem* download = GetDownloadById(id); |
625 if (download) | 334 if (download) |
626 download->Remove(); | 335 download->Remove(); |
627 } | 336 } |
628 } | 337 } |
629 } | 338 } |
630 | 339 |
631 void MdDownloadsDOMHandler::SendCurrentDownloads() { | |
632 update_scheduled_ = false; | |
633 | |
634 content::DownloadManager::DownloadVector all_items, filtered_items; | |
635 if (GetMainNotifierManager()) { | |
636 GetMainNotifierManager()->GetAllDownloads(&all_items); | |
637 GetMainNotifierManager()->CheckForHistoryFilesRemoval(); | |
Dan Beam
2016/01/21 02:21:42
^ well, I dropped this on the floor
| |
638 } | |
639 if (GetOriginalNotifierManager()) { | |
640 GetOriginalNotifierManager()->GetAllDownloads(&all_items); | |
641 GetOriginalNotifierManager()->CheckForHistoryFilesRemoval(); | |
642 } | |
643 | |
644 DownloadQuery query; | |
645 if (search_terms_ && !search_terms_->empty()) | |
646 query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_); | |
647 query.AddFilter(base::Bind(&IsDownloadDisplayable)); | |
648 query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING); | |
649 query.Limit(kMaxNumberOfDownloads); | |
650 query.Search(all_items.begin(), all_items.end(), &filtered_items); | |
651 | |
652 base::ListValue results_value; | |
653 for (auto* item : filtered_items) { | |
654 results_value.Append(CreateDownloadItemValue( | |
655 item, | |
656 original_notifier_ && GetMainNotifierManager() && | |
657 GetMainNotifierManager()->GetDownload(item->GetId()) == item)); | |
658 } | |
659 CallUpdateAll(results_value); | |
660 } | |
661 | |
662 void MdDownloadsDOMHandler::ShowDangerPrompt( | 340 void MdDownloadsDOMHandler::ShowDangerPrompt( |
663 content::DownloadItem* dangerous_item) { | 341 content::DownloadItem* dangerous_item) { |
664 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( | 342 DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( |
665 dangerous_item, | 343 dangerous_item, |
666 GetWebUIWebContents(), | 344 GetWebUIWebContents(), |
667 false, | 345 false, |
668 base::Bind(&MdDownloadsDOMHandler::DangerPromptDone, | 346 base::Bind(&MdDownloadsDOMHandler::DangerPromptDone, |
669 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId())); | 347 weak_ptr_factory_.GetWeakPtr(), dangerous_item->GetId())); |
670 // danger_prompt will delete itself. | 348 // danger_prompt will delete itself. |
671 DCHECK(danger_prompt); | 349 DCHECK(danger_prompt); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 if (GetMainNotifierManager()) | 393 if (GetMainNotifierManager()) |
716 item = GetMainNotifierManager()->GetDownload(id); | 394 item = GetMainNotifierManager()->GetDownload(id); |
717 if (!item && GetOriginalNotifierManager()) | 395 if (!item && GetOriginalNotifierManager()) |
718 item = GetOriginalNotifierManager()->GetDownload(id); | 396 item = GetOriginalNotifierManager()->GetDownload(id); |
719 return item; | 397 return item; |
720 } | 398 } |
721 | 399 |
722 content::WebContents* MdDownloadsDOMHandler::GetWebUIWebContents() { | 400 content::WebContents* MdDownloadsDOMHandler::GetWebUIWebContents() { |
723 return web_ui()->GetWebContents(); | 401 return web_ui()->GetWebContents(); |
724 } | 402 } |
725 | |
726 void MdDownloadsDOMHandler::CallUpdateAll(const base::ListValue& list) { | |
727 web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list); | |
728 } | |
729 | |
730 void MdDownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue& item) { | |
731 web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item); | |
732 } | |
OLD | NEW |