| 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/chromeos/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("uncommoncontent", | |
| 89 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT); | |
| 90 source->AddLocalizedString("cancel", IDS_DOWNLOAD_LINK_CANCEL); | |
| 91 source->AddLocalizedString("discard", IDS_DISCARD_DOWNLOAD); | |
| 92 source->AddLocalizedString("continue", IDS_CONTINUE_EXTENSION_DOWNLOAD); | |
| 93 source->AddLocalizedString("pause", IDS_DOWNLOAD_LINK_PAUSE); | |
| 94 source->AddLocalizedString("resume", IDS_DOWNLOAD_LINK_RESUME); | |
| 95 source->AddLocalizedString("showallfiles", | |
| 96 IDS_FILE_BROWSER_MORE_FILES); | |
| 97 source->AddLocalizedString("error_unknown_file_type", | |
| 98 IDS_FILE_BROWSER_ERROR_UNKNOWN_FILE_TYPE); | |
| 99 | |
| 100 FilePath default_download_path; | |
| 101 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, | |
| 102 &default_download_path)) { | |
| 103 NOTREACHED(); | |
| 104 } | |
| 105 // TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode. | |
| 106 source->AddString("downloadpath", UTF8ToUTF16(default_download_path.value())); | |
| 107 | |
| 108 source->set_json_path("strings.js"); | |
| 109 source->add_resource_path("active_downloads.js", IDR_ACTIVE_DOWNLOADS_JS); | |
| 110 source->set_default_resource(IDR_ACTIVE_DOWNLOADS_HTML); | |
| 111 return source; | |
| 112 } | |
| 113 | |
| 114 } // namespace | |
| 115 | |
| 116 using content::DownloadItem; | |
| 117 using content::DownloadManager; | |
| 118 | |
| 119 //////////////////////////////////////////////////////////////////////////////// | |
| 120 // | |
| 121 // ActiveDownloadsHandler | |
| 122 // | |
| 123 //////////////////////////////////////////////////////////////////////////////// | |
| 124 | |
| 125 // The handler for Javascript messages related to the "active_downloads" view. | |
| 126 class ActiveDownloadsHandler | |
| 127 : public WebUIMessageHandler, | |
| 128 public DownloadManager::Observer, | |
| 129 public DownloadItem::Observer { | |
| 130 public: | |
| 131 ActiveDownloadsHandler(); | |
| 132 virtual ~ActiveDownloadsHandler(); | |
| 133 | |
| 134 // WebUIMessageHandler implementation. | |
| 135 virtual void RegisterMessages() OVERRIDE; | |
| 136 | |
| 137 // DownloadItem::Observer interface. | |
| 138 virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE; | |
| 139 virtual void OnDownloadOpened(DownloadItem* item) OVERRIDE { } | |
| 140 | |
| 141 // DownloadManager::Observer interface. | |
| 142 virtual void ModelChanged(DownloadManager* manager) OVERRIDE; | |
| 143 | |
| 144 // WebUI Callbacks. | |
| 145 void HandleGetDownloads(const ListValue* args); | |
| 146 void HandlePauseToggleDownload(const ListValue* args); | |
| 147 void HandleAllowDownload(const ListValue* args); | |
| 148 void HandleCancelDownload(const ListValue* args); | |
| 149 void HandleShowAllFiles(const ListValue* args); | |
| 150 void ViewFile(const ListValue* args); | |
| 151 | |
| 152 // For testing. | |
| 153 typedef std::vector<DownloadItem*> DownloadList; | |
| 154 const DownloadList& downloads() const { return downloads_; } | |
| 155 | |
| 156 private: | |
| 157 // Downloads helpers. | |
| 158 DownloadItem* GetDownloadById(const ListValue* args); | |
| 159 void UpdateDownloadList(); | |
| 160 void SendDownloads(); | |
| 161 void AddDownload(DownloadItem* item); | |
| 162 | |
| 163 Profile* profile_; | |
| 164 DownloadManager* download_manager_; | |
| 165 | |
| 166 DownloadList active_downloads_; | |
| 167 DownloadList downloads_; | |
| 168 | |
| 169 DISALLOW_COPY_AND_ASSIGN(ActiveDownloadsHandler); | |
| 170 }; | |
| 171 | |
| 172 ActiveDownloadsHandler::ActiveDownloadsHandler() | |
| 173 : profile_(NULL), | |
| 174 download_manager_(NULL) { | |
| 175 } | |
| 176 | |
| 177 ActiveDownloadsHandler::~ActiveDownloadsHandler() { | |
| 178 for (size_t i = 0; i < downloads_.size(); ++i) { | |
| 179 downloads_[i]->RemoveObserver(this); | |
| 180 } | |
| 181 download_manager_->RemoveObserver(this); | |
| 182 } | |
| 183 | |
| 184 void ActiveDownloadsHandler::RegisterMessages() { | |
| 185 profile_ = Profile::FromWebUI(web_ui()); | |
| 186 profile_->GetChromeURLDataManager()->AddDataSource(new FileIconSource()); | |
| 187 | |
| 188 web_ui()->RegisterMessageCallback("getDownloads", | |
| 189 base::Bind(&ActiveDownloadsHandler::HandleGetDownloads, | |
| 190 base::Unretained(this))); | |
| 191 web_ui()->RegisterMessageCallback("pauseToggleDownload", | |
| 192 base::Bind(&ActiveDownloadsHandler::HandlePauseToggleDownload, | |
| 193 base::Unretained(this))); | |
| 194 web_ui()->RegisterMessageCallback("allowDownload", | |
| 195 base::Bind(&ActiveDownloadsHandler::HandleAllowDownload, | |
| 196 base::Unretained(this))); | |
| 197 web_ui()->RegisterMessageCallback("cancelDownload", | |
| 198 base::Bind(&ActiveDownloadsHandler::HandleCancelDownload, | |
| 199 base::Unretained(this))); | |
| 200 web_ui()->RegisterMessageCallback("showAllFiles", | |
| 201 base::Bind(&ActiveDownloadsHandler::HandleShowAllFiles, | |
| 202 base::Unretained(this))); | |
| 203 web_ui()->RegisterMessageCallback("viewFile", | |
| 204 base::Bind(&ActiveDownloadsHandler::ViewFile, | |
| 205 base::Unretained(this))); | |
| 206 | |
| 207 download_manager_ = | |
| 208 DownloadServiceFactory::GetForProfile(profile_)->GetDownloadManager(); | |
| 209 download_manager_->AddObserver(this); | |
| 210 } | |
| 211 | |
| 212 DownloadItem* ActiveDownloadsHandler::GetDownloadById( | |
| 213 const ListValue* args) { | |
| 214 int i; | |
| 215 if (!ExtractIntegerValue(args, &i)) | |
| 216 return NULL; | |
| 217 size_t id(i); | |
| 218 return id < downloads_.size() ? downloads_[id] : NULL; | |
| 219 } | |
| 220 | |
| 221 void ActiveDownloadsHandler::HandlePauseToggleDownload(const ListValue* args) { | |
| 222 DownloadItem* item = GetDownloadById(args); | |
| 223 if (item && item->IsPartialDownload()) | |
| 224 item->TogglePause(); | |
| 225 } | |
| 226 | |
| 227 void ActiveDownloadsHandler::HandleAllowDownload(const ListValue* args) { | |
| 228 DownloadItem* item = GetDownloadById(args); | |
| 229 if (item) | |
| 230 item->DangerousDownloadValidated(); | |
| 231 } | |
| 232 | |
| 233 void ActiveDownloadsHandler::HandleCancelDownload(const ListValue* args) { | |
| 234 DownloadItem* item = GetDownloadById(args); | |
| 235 if (item) { | |
| 236 if (item->IsPartialDownload()) | |
| 237 item->Cancel(true); | |
| 238 item->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 void ActiveDownloadsHandler::HandleShowAllFiles(const ListValue* args) { | |
| 243 file_manager_util::ViewFolder( | |
| 244 DownloadPrefs::FromDownloadManager(download_manager_)->download_path()); | |
| 245 } | |
| 246 | |
| 247 void ActiveDownloadsHandler::ViewFile(const ListValue* args) { | |
| 248 file_manager_util::ViewFile(FilePath(UTF16ToUTF8(ExtractStringValue(args))), | |
| 249 false); | |
| 250 } | |
| 251 | |
| 252 void ActiveDownloadsHandler::ModelChanged(DownloadManager* manager) { | |
| 253 UpdateDownloadList(); | |
| 254 } | |
| 255 | |
| 256 void ActiveDownloadsHandler::HandleGetDownloads(const ListValue* args) { | |
| 257 UpdateDownloadList(); | |
| 258 } | |
| 259 | |
| 260 void ActiveDownloadsHandler::UpdateDownloadList() { | |
| 261 DownloadList downloads; | |
| 262 download_manager_->GetAllDownloads(FilePath(), &downloads); | |
| 263 active_downloads_.clear(); | |
| 264 for (size_t i = 0; i < downloads.size(); ++i) { | |
| 265 AddDownload(downloads[i]); | |
| 266 } | |
| 267 SendDownloads(); | |
| 268 } | |
| 269 | |
| 270 void ActiveDownloadsHandler::AddDownload(DownloadItem* item) { | |
| 271 // Observe in progress and dangerous downloads. | |
| 272 if (item->GetState() == DownloadItem::IN_PROGRESS || | |
| 273 item->GetSafetyState() == DownloadItem::DANGEROUS) { | |
| 274 active_downloads_.push_back(item); | |
| 275 | |
| 276 DownloadList::const_iterator it = | |
| 277 std::find(downloads_.begin(), downloads_.end(), item); | |
| 278 if (it == downloads_.end()) { | |
| 279 downloads_.push_back(item); | |
| 280 item->AddObserver(this); | |
| 281 } | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 void ActiveDownloadsHandler::SendDownloads() { | |
| 286 ListValue results; | |
| 287 for (size_t i = 0; i < downloads_.size(); ++i) { | |
| 288 results.Append(download_util::CreateDownloadItemValue(downloads_[i], i)); | |
| 289 } | |
| 290 | |
| 291 web_ui()->CallJavascriptFunction("downloadsList", results); | |
| 292 } | |
| 293 | |
| 294 void ActiveDownloadsHandler::OnDownloadUpdated(DownloadItem* item) { | |
| 295 DownloadList::iterator it = | |
| 296 find(downloads_.begin(), downloads_.end(), item); | |
| 297 | |
| 298 if (it == downloads_.end()) { | |
| 299 NOTREACHED() << "Updated item " << item->GetFullPath().value() | |
| 300 << " not found"; | |
| 301 } | |
| 302 | |
| 303 if (item->GetState() == DownloadItem::REMOVING || item->GetAutoOpened()) { | |
| 304 // Item is going away, or item is an extension that has auto opened. | |
| 305 item->RemoveObserver(this); | |
| 306 downloads_.erase(it); | |
| 307 DownloadList::iterator ita = | |
| 308 find(active_downloads_.begin(), active_downloads_.end(), item); | |
| 309 if (ita != active_downloads_.end()) | |
| 310 active_downloads_.erase(ita); | |
| 311 SendDownloads(); | |
| 312 } else { | |
| 313 const size_t id = it - downloads_.begin(); | |
| 314 scoped_ptr<DictionaryValue> result( | |
| 315 download_util::CreateDownloadItemValue(item, id)); | |
| 316 web_ui()->CallJavascriptFunction("downloadUpdated", *result); | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 //////////////////////////////////////////////////////////////////////////////// | |
| 321 // | |
| 322 // ActiveDownloadsUI | |
| 323 // | |
| 324 //////////////////////////////////////////////////////////////////////////////// | |
| 325 | |
| 326 | |
| 327 ActiveDownloadsUI::ActiveDownloadsUI(content::WebUI* web_ui) | |
| 328 : HtmlDialogUI(web_ui), | |
| 329 handler_(new ActiveDownloadsHandler()) { | |
| 330 web_ui->AddMessageHandler(handler_); | |
| 331 | |
| 332 // Set up the chrome://active-downloads/ source. | |
| 333 Profile* profile = Profile::FromWebUI(web_ui); | |
| 334 profile->GetChromeURLDataManager()->AddDataSource( | |
| 335 CreateActiveDownloadsUIHTMLSource()); | |
| 336 } | |
| 337 | |
| 338 // static | |
| 339 bool ActiveDownloadsUI::ShouldShowPopup(Profile* profile, | |
| 340 DownloadItem* download) { | |
| 341 // Don't show downloads panel for extension/theme downloads from gallery, | |
| 342 // or temporary downloads. | |
| 343 ExtensionService* service = profile->GetExtensionService(); | |
| 344 return !download->IsTemporary() && | |
| 345 (!ChromeDownloadManagerDelegate::IsExtensionDownload(download) || | |
| 346 service == NULL || | |
| 347 !service->IsDownloadFromGallery(download->GetURL(), | |
| 348 download->GetReferrerUrl())); | |
| 349 } | |
| 350 | |
| 351 // static | |
| 352 Browser* ActiveDownloadsUI::OpenPopup(Profile* profile) { | |
| 353 Browser* browser = GetPopup(); | |
| 354 | |
| 355 // Create new browser if no matching pop up is found. | |
| 356 if (browser == NULL) { | |
| 357 browser = Browser::CreateWithParams( | |
| 358 Browser::CreateParams::CreateForApp( | |
| 359 Browser::TYPE_PANEL, kActiveDownloadAppName, gfx::Rect(), profile)); | |
| 360 | |
| 361 browser::NavigateParams params( | |
| 362 browser, | |
| 363 GURL(chrome::kChromeUIActiveDownloadsURL), | |
| 364 content::PAGE_TRANSITION_LINK); | |
| 365 params.disposition = NEW_FOREGROUND_TAB; | |
| 366 browser::Navigate(¶ms); | |
| 367 | |
| 368 DCHECK_EQ(browser, params.browser); | |
| 369 // TODO(beng): The following two calls should be automatic by Navigate(). | |
| 370 browser->window()->SetBounds(gfx::Rect(kPopupLeft, | |
| 371 kPopupTop, | |
| 372 kPopupWidth, | |
| 373 kPopupHeight)); | |
| 374 } | |
| 375 | |
| 376 browser->window()->Show(); | |
| 377 return browser; | |
| 378 } | |
| 379 | |
| 380 // static | |
| 381 Browser* ActiveDownloadsUI::GetPopup() { | |
| 382 for (BrowserList::const_iterator it = BrowserList::begin(); | |
| 383 it != BrowserList::end(); | |
| 384 ++it) { | |
| 385 if ((*it)->is_type_panel() && (*it)->is_app()) { | |
| 386 WebContents* web_contents = (*it)->GetSelectedWebContents(); | |
| 387 DCHECK(web_contents); | |
| 388 if (!web_contents) | |
| 389 continue; | |
| 390 const GURL& url = web_contents->GetURL(); | |
| 391 | |
| 392 if (url.SchemeIs(chrome::kChromeUIScheme) && | |
| 393 url.host() == chrome::kChromeUIActiveDownloadsHost) { | |
| 394 return (*it); | |
| 395 } | |
| 396 } | |
| 397 } | |
| 398 return NULL; | |
| 399 } | |
| 400 | |
| 401 const ActiveDownloadsUI::DownloadList& ActiveDownloadsUI::GetDownloads() const { | |
| 402 return handler_->downloads(); | |
| 403 } | |
| OLD | NEW |