| OLD | NEW |
| (Empty) |
| 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/active_downloads_ui.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/bind_helpers.h" | |
| 13 #include "base/command_line.h" | |
| 14 #include "base/file_util.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/memory/singleton.h" | |
| 17 #include "base/message_loop.h" | |
| 18 #include "base/path_service.h" | |
| 19 #include "base/string_piece.h" | |
| 20 #include "base/string_util.h" | |
| 21 #include "base/threading/thread.h" | |
| 22 #include "base/time.h" | |
| 23 #include "base/utf_string_conversions.h" | |
| 24 #include "base/values.h" | |
| 25 #include "chrome/browser/chromeos/cros/cros_library.h" | |
| 26 #include "chrome/browser/chromeos/extensions/file_manager_util.h" | |
| 27 #include "chrome/browser/chromeos/media/media_player.h" | |
| 28 #include "chrome/browser/download/chrome_download_manager_delegate.h" | |
| 29 #include "chrome/browser/download/download_prefs.h" | |
| 30 #include "chrome/browser/download/download_service.h" | |
| 31 #include "chrome/browser/download/download_service_factory.h" | |
| 32 #include "chrome/browser/download/download_util.h" | |
| 33 #include "chrome/browser/extensions/extension_service.h" | |
| 34 #include "chrome/browser/profiles/profile.h" | |
| 35 #include "chrome/browser/tabs/tab_strip_model.h" | |
| 36 #include "chrome/browser/ui/browser.h" | |
| 37 #include "chrome/browser/ui/browser_list.h" | |
| 38 #include "chrome/browser/ui/browser_window.h" | |
| 39 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
| 40 #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h" | |
| 41 #include "chrome/browser/ui/webui/fileicon_source.h" | |
| 42 #include "chrome/common/chrome_paths.h" | |
| 43 #include "chrome/common/chrome_switches.h" | |
| 44 #include "chrome/common/url_constants.h" | |
| 45 #include "content/public/browser/download_item.h" | |
| 46 #include "content/public/browser/download_manager.h" | |
| 47 #include "content/public/browser/navigation_controller.h" | |
| 48 #include "content/public/browser/render_view_host.h" | |
| 49 #include "content/public/browser/render_view_host_delegate.h" | |
| 50 #include "content/public/browser/web_contents.h" | |
| 51 #include "content/public/browser/web_ui.h" | |
| 52 #include "content/public/browser/web_ui_message_handler.h" | |
| 53 #include "grit/browser_resources.h" | |
| 54 #include "grit/chromium_strings.h" | |
| 55 #include "grit/generated_resources.h" | |
| 56 #include "grit/locale_settings.h" | |
| 57 #include "net/base/escape.h" | |
| 58 #include "net/url_request/url_request_file_job.h" | |
| 59 #include "ui/base/resource/resource_bundle.h" | |
| 60 | |
| 61 using content::WebContents; | |
| 62 using content::WebUIMessageHandler; | |
| 63 | |
| 64 namespace { | |
| 65 | |
| 66 static const int kPopupLeft = 0; | |
| 67 static const int kPopupTop = 0; | |
| 68 static const int kPopupWidth = 250; | |
| 69 // Minimum height of window must be 100, so kPopupHeight has space for | |
| 70 // 2 download rows of 36 px and 'Show all files' link which is 29px. | |
| 71 static const int kPopupHeight = 36 * 2 + 29; | |
| 72 | |
| 73 static const char kPropertyPath[] = "path"; | |
| 74 static const char kPropertyTitle[] = "title"; | |
| 75 static const char kPropertyDirectory[] = "isDirectory"; | |
| 76 static const char kActiveDownloadAppName[] = "active-downloads"; | |
| 77 | |
| 78 ChromeWebUIDataSource* CreateActiveDownloadsUIHTMLSource() { | |
| 79 ChromeWebUIDataSource* source = | |
| 80 new ChromeWebUIDataSource(chrome::kChromeUIActiveDownloadsHost); | |
| 81 | |
| 82 source->AddLocalizedString("dangerousfile", IDS_PROMPT_DANGEROUS_DOWNLOAD); | |
| 83 source->AddLocalizedString("dangerousextension", | |
| 84 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION); | |
| 85 source->AddLocalizedString("dangerousurl", IDS_PROMPT_MALICIOUS_DOWNLOAD_URL); | |
| 86 source->AddLocalizedString("dangerouscontent", | |
| 87 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT); | |
| 88 source->AddLocalizedString("cancel", IDS_DOWNLOAD_LINK_CANCEL); | |
| 89 source->AddLocalizedString("discard", IDS_DISCARD_DOWNLOAD); | |
| 90 source->AddLocalizedString("continue", IDS_CONTINUE_EXTENSION_DOWNLOAD); | |
| 91 source->AddLocalizedString("pause", IDS_DOWNLOAD_LINK_PAUSE); | |
| 92 source->AddLocalizedString("resume", IDS_DOWNLOAD_LINK_RESUME); | |
| 93 source->AddLocalizedString("showallfiles", | |
| 94 IDS_FILE_BROWSER_MORE_FILES); | |
| 95 source->AddLocalizedString("error_unknown_file_type", | |
| 96 IDS_FILE_BROWSER_ERROR_UNKNOWN_FILE_TYPE); | |
| 97 | |
| 98 FilePath default_download_path; | |
| 99 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, | |
| 100 &default_download_path)) { | |
| 101 NOTREACHED(); | |
| 102 } | |
| 103 // TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode. | |
| 104 source->AddString("downloadpath", UTF8ToUTF16(default_download_path.value())); | |
| 105 | |
| 106 source->set_json_path("strings.js"); | |
| 107 source->add_resource_path("active_downloads.js", IDR_ACTIVE_DOWNLOADS_JS); | |
| 108 source->set_default_resource(IDR_ACTIVE_DOWNLOADS_HTML); | |
| 109 return source; | |
| 110 } | |
| 111 | |
| 112 } // namespace | |
| 113 | |
| 114 using content::DownloadItem; | |
| 115 using content::DownloadManager; | |
| 116 | |
| 117 //////////////////////////////////////////////////////////////////////////////// | |
| 118 // | |
| 119 // ActiveDownloadsHandler | |
| 120 // | |
| 121 //////////////////////////////////////////////////////////////////////////////// | |
| 122 | |
| 123 // The handler for Javascript messages related to the "active_downloads" view. | |
| 124 class ActiveDownloadsHandler | |
| 125 : public WebUIMessageHandler, | |
| 126 public DownloadManager::Observer, | |
| 127 public DownloadItem::Observer { | |
| 128 public: | |
| 129 ActiveDownloadsHandler(); | |
| 130 virtual ~ActiveDownloadsHandler(); | |
| 131 | |
| 132 // WebUIMessageHandler implementation. | |
| 133 virtual void RegisterMessages() OVERRIDE; | |
| 134 | |
| 135 // DownloadItem::Observer interface. | |
| 136 virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE; | |
| 137 virtual void OnDownloadOpened(DownloadItem* item) OVERRIDE { } | |
| 138 | |
| 139 // DownloadManager::Observer interface. | |
| 140 virtual void ModelChanged(DownloadManager* manager) OVERRIDE; | |
| 141 | |
| 142 // WebUI Callbacks. | |
| 143 void HandleGetDownloads(const ListValue* args); | |
| 144 void HandlePauseToggleDownload(const ListValue* args); | |
| 145 void HandleAllowDownload(const ListValue* args); | |
| 146 void HandleCancelDownload(const ListValue* args); | |
| 147 void HandleShowAllFiles(const ListValue* args); | |
| 148 void ViewFile(const ListValue* args); | |
| 149 | |
| 150 // For testing. | |
| 151 typedef std::vector<DownloadItem*> DownloadList; | |
| 152 const DownloadList& downloads() const { return downloads_; } | |
| 153 | |
| 154 private: | |
| 155 // Downloads helpers. | |
| 156 DownloadItem* GetDownloadById(const ListValue* args); | |
| 157 void UpdateDownloadList(); | |
| 158 void SendDownloads(); | |
| 159 void AddDownload(DownloadItem* item); | |
| 160 | |
| 161 Profile* profile_; | |
| 162 DownloadManager* download_manager_; | |
| 163 | |
| 164 DownloadList active_downloads_; | |
| 165 DownloadList downloads_; | |
| 166 | |
| 167 DISALLOW_COPY_AND_ASSIGN(ActiveDownloadsHandler); | |
| 168 }; | |
| 169 | |
| 170 ActiveDownloadsHandler::ActiveDownloadsHandler() | |
| 171 : profile_(NULL), | |
| 172 download_manager_(NULL) { | |
| 173 } | |
| 174 | |
| 175 ActiveDownloadsHandler::~ActiveDownloadsHandler() { | |
| 176 for (size_t i = 0; i < downloads_.size(); ++i) { | |
| 177 downloads_[i]->RemoveObserver(this); | |
| 178 } | |
| 179 download_manager_->RemoveObserver(this); | |
| 180 } | |
| 181 | |
| 182 void ActiveDownloadsHandler::RegisterMessages() { | |
| 183 profile_ = Profile::FromWebUI(web_ui()); | |
| 184 profile_->GetChromeURLDataManager()->AddDataSource(new FileIconSource()); | |
| 185 | |
| 186 web_ui()->RegisterMessageCallback("getDownloads", | |
| 187 base::Bind(&ActiveDownloadsHandler::HandleGetDownloads, | |
| 188 base::Unretained(this))); | |
| 189 web_ui()->RegisterMessageCallback("pauseToggleDownload", | |
| 190 base::Bind(&ActiveDownloadsHandler::HandlePauseToggleDownload, | |
| 191 base::Unretained(this))); | |
| 192 web_ui()->RegisterMessageCallback("allowDownload", | |
| 193 base::Bind(&ActiveDownloadsHandler::HandleAllowDownload, | |
| 194 base::Unretained(this))); | |
| 195 web_ui()->RegisterMessageCallback("cancelDownload", | |
| 196 base::Bind(&ActiveDownloadsHandler::HandleCancelDownload, | |
| 197 base::Unretained(this))); | |
| 198 web_ui()->RegisterMessageCallback("showAllFiles", | |
| 199 base::Bind(&ActiveDownloadsHandler::HandleShowAllFiles, | |
| 200 base::Unretained(this))); | |
| 201 web_ui()->RegisterMessageCallback("viewFile", | |
| 202 base::Bind(&ActiveDownloadsHandler::ViewFile, | |
| 203 base::Unretained(this))); | |
| 204 | |
| 205 download_manager_ = | |
| 206 DownloadServiceFactory::GetForProfile(profile_)->GetDownloadManager(); | |
| 207 download_manager_->AddObserver(this); | |
| 208 } | |
| 209 | |
| 210 DownloadItem* ActiveDownloadsHandler::GetDownloadById( | |
| 211 const ListValue* args) { | |
| 212 int i; | |
| 213 if (!ExtractIntegerValue(args, &i)) | |
| 214 return NULL; | |
| 215 size_t id(i); | |
| 216 return id < downloads_.size() ? downloads_[id] : NULL; | |
| 217 } | |
| 218 | |
| 219 void ActiveDownloadsHandler::HandlePauseToggleDownload(const ListValue* args) { | |
| 220 DownloadItem* item = GetDownloadById(args); | |
| 221 if (item && item->IsPartialDownload()) | |
| 222 item->TogglePause(); | |
| 223 } | |
| 224 | |
| 225 void ActiveDownloadsHandler::HandleAllowDownload(const ListValue* args) { | |
| 226 DownloadItem* item = GetDownloadById(args); | |
| 227 if (item) | |
| 228 item->DangerousDownloadValidated(); | |
| 229 } | |
| 230 | |
| 231 void ActiveDownloadsHandler::HandleCancelDownload(const ListValue* args) { | |
| 232 DownloadItem* item = GetDownloadById(args); | |
| 233 if (item) { | |
| 234 if (item->IsPartialDownload()) | |
| 235 item->Cancel(true); | |
| 236 item->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 void ActiveDownloadsHandler::HandleShowAllFiles(const ListValue* args) { | |
| 241 file_manager_util::ViewFolder( | |
| 242 DownloadPrefs::FromDownloadManager(download_manager_)->download_path()); | |
| 243 } | |
| 244 | |
| 245 void ActiveDownloadsHandler::ViewFile(const ListValue* args) { | |
| 246 file_manager_util::ViewFile(FilePath(UTF16ToUTF8(ExtractStringValue(args))), | |
| 247 false); | |
| 248 } | |
| 249 | |
| 250 void ActiveDownloadsHandler::ModelChanged(DownloadManager* manager) { | |
| 251 UpdateDownloadList(); | |
| 252 } | |
| 253 | |
| 254 void ActiveDownloadsHandler::HandleGetDownloads(const ListValue* args) { | |
| 255 UpdateDownloadList(); | |
| 256 } | |
| 257 | |
| 258 void ActiveDownloadsHandler::UpdateDownloadList() { | |
| 259 DownloadList downloads; | |
| 260 download_manager_->GetAllDownloads(FilePath(), &downloads); | |
| 261 active_downloads_.clear(); | |
| 262 for (size_t i = 0; i < downloads.size(); ++i) { | |
| 263 AddDownload(downloads[i]); | |
| 264 } | |
| 265 SendDownloads(); | |
| 266 } | |
| 267 | |
| 268 void ActiveDownloadsHandler::AddDownload(DownloadItem* item) { | |
| 269 // Observe in progress and dangerous downloads. | |
| 270 if (item->GetState() == DownloadItem::IN_PROGRESS || | |
| 271 item->GetSafetyState() == DownloadItem::DANGEROUS) { | |
| 272 active_downloads_.push_back(item); | |
| 273 | |
| 274 DownloadList::const_iterator it = | |
| 275 std::find(downloads_.begin(), downloads_.end(), item); | |
| 276 if (it == downloads_.end()) { | |
| 277 downloads_.push_back(item); | |
| 278 item->AddObserver(this); | |
| 279 } | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 void ActiveDownloadsHandler::SendDownloads() { | |
| 284 ListValue results; | |
| 285 for (size_t i = 0; i < downloads_.size(); ++i) { | |
| 286 results.Append(download_util::CreateDownloadItemValue(downloads_[i], i)); | |
| 287 } | |
| 288 | |
| 289 web_ui()->CallJavascriptFunction("downloadsList", results); | |
| 290 } | |
| 291 | |
| 292 void ActiveDownloadsHandler::OnDownloadUpdated(DownloadItem* item) { | |
| 293 DownloadList::iterator it = | |
| 294 find(downloads_.begin(), downloads_.end(), item); | |
| 295 | |
| 296 if (it == downloads_.end()) { | |
| 297 NOTREACHED() << "Updated item " << item->GetFullPath().value() | |
| 298 << " not found"; | |
| 299 } | |
| 300 | |
| 301 if (item->GetState() == DownloadItem::REMOVING || item->GetAutoOpened()) { | |
| 302 // Item is going away, or item is an extension that has auto opened. | |
| 303 item->RemoveObserver(this); | |
| 304 downloads_.erase(it); | |
| 305 DownloadList::iterator ita = | |
| 306 find(active_downloads_.begin(), active_downloads_.end(), item); | |
| 307 if (ita != active_downloads_.end()) | |
| 308 active_downloads_.erase(ita); | |
| 309 SendDownloads(); | |
| 310 } else { | |
| 311 const size_t id = it - downloads_.begin(); | |
| 312 scoped_ptr<DictionaryValue> result( | |
| 313 download_util::CreateDownloadItemValue(item, id)); | |
| 314 web_ui()->CallJavascriptFunction("downloadUpdated", *result); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 //////////////////////////////////////////////////////////////////////////////// | |
| 319 // | |
| 320 // ActiveDownloadsUI | |
| 321 // | |
| 322 //////////////////////////////////////////////////////////////////////////////// | |
| 323 | |
| 324 | |
| 325 ActiveDownloadsUI::ActiveDownloadsUI(content::WebUI* web_ui) | |
| 326 : HtmlDialogUI(web_ui), | |
| 327 handler_(new ActiveDownloadsHandler()) { | |
| 328 web_ui->AddMessageHandler(handler_); | |
| 329 | |
| 330 // Set up the chrome://active-downloads/ source. | |
| 331 Profile* profile = Profile::FromWebUI(web_ui); | |
| 332 profile->GetChromeURLDataManager()->AddDataSource( | |
| 333 CreateActiveDownloadsUIHTMLSource()); | |
| 334 } | |
| 335 | |
| 336 // static | |
| 337 bool ActiveDownloadsUI::ShouldShowPopup(Profile* profile, | |
| 338 DownloadItem* download) { | |
| 339 // Don't show downloads panel for extension/theme downloads from gallery, | |
| 340 // or temporary downloads. | |
| 341 ExtensionService* service = profile->GetExtensionService(); | |
| 342 return !download->IsTemporary() && | |
| 343 (!ChromeDownloadManagerDelegate::IsExtensionDownload(download) || | |
| 344 service == NULL || | |
| 345 !service->IsDownloadFromGallery(download->GetURL(), | |
| 346 download->GetReferrerUrl())); | |
| 347 } | |
| 348 | |
| 349 // static | |
| 350 Browser* ActiveDownloadsUI::OpenPopup(Profile* profile) { | |
| 351 Browser* browser = GetPopup(); | |
| 352 | |
| 353 // Create new browser if no matching pop up is found. | |
| 354 if (browser == NULL) { | |
| 355 browser = Browser::CreateForApp(Browser::TYPE_PANEL, kActiveDownloadAppName, | |
| 356 gfx::Rect(), profile); | |
| 357 | |
| 358 browser::NavigateParams params( | |
| 359 browser, | |
| 360 GURL(chrome::kChromeUIActiveDownloadsURL), | |
| 361 content::PAGE_TRANSITION_LINK); | |
| 362 params.disposition = NEW_FOREGROUND_TAB; | |
| 363 browser::Navigate(¶ms); | |
| 364 | |
| 365 DCHECK_EQ(browser, params.browser); | |
| 366 // TODO(beng): The following two calls should be automatic by Navigate(). | |
| 367 browser->window()->SetBounds(gfx::Rect(kPopupLeft, | |
| 368 kPopupTop, | |
| 369 kPopupWidth, | |
| 370 kPopupHeight)); | |
| 371 } | |
| 372 | |
| 373 browser->window()->Show(); | |
| 374 return browser; | |
| 375 } | |
| 376 | |
| 377 // static | |
| 378 Browser* ActiveDownloadsUI::GetPopup() { | |
| 379 for (BrowserList::const_iterator it = BrowserList::begin(); | |
| 380 it != BrowserList::end(); | |
| 381 ++it) { | |
| 382 if ((*it)->is_type_panel() && (*it)->is_app()) { | |
| 383 WebContents* web_contents = (*it)->GetSelectedWebContents(); | |
| 384 DCHECK(web_contents); | |
| 385 if (!web_contents) | |
| 386 continue; | |
| 387 const GURL& url = web_contents->GetURL(); | |
| 388 | |
| 389 if (url.SchemeIs(chrome::kChromeUIScheme) && | |
| 390 url.host() == chrome::kChromeUIActiveDownloadsHost) { | |
| 391 return (*it); | |
| 392 } | |
| 393 } | |
| 394 } | |
| 395 return NULL; | |
| 396 } | |
| 397 | |
| 398 const ActiveDownloadsUI::DownloadList& ActiveDownloadsUI::GetDownloads() const { | |
| 399 return handler_->downloads(); | |
| 400 } | |
| OLD | NEW |