1 // Copyright 2013 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/download/download_ui_controller.h" 6 7 #include "base/callback.h" 8 #include "base/stl_util.h" 9 #include "chrome/browser/download/download_item_model.h" 10 #include "chrome/browser/ui/browser_finder.h" 11 #include "chrome/browser/ui/browser_tabstrip.h" 12 #include "content/public/browser/download_item.h" 13 #include "content/public/browser/web_contents.h" 14 #include "content/public/browser/web_contents_delegate.h" 15 16 #if defined(OS_ANDROID) 17 #include "content/public/browser/android/download_controller_android.h" 18 #else 19 #include "chrome/browser/profiles/profile.h" 20 #endif 21 22 namespace { 23 24 // DefaultUIControllerDelegate{Android,} is used when a DownloadUIController is 25 // constructed without specifying an explicit Delegate. 26 #if defined(OS_ANDROID) 27 28 class DefaultUIControllerDelegateAndroid 29 : public DownloadUIController::Delegate { 30 public: 31 DefaultUIControllerDelegateAndroid() {} 32 virtual ~DefaultUIControllerDelegateAndroid() {} 33 34 private: 35 // DownloadUIController::Delegate 36 virtual void OnNewDownloadReady(content::DownloadItem* item) OVERRIDE; 37 }; 38 39 void DefaultUIControllerDelegateAndroid::OnNewDownloadReady( 40 content::DownloadItem* item) { 41 // The Android DownloadController is only interested in IN_PROGRESS downloads. 42 // Ones which are INTERRUPTED etc. can't be handed over to the Android 43 // DownloadManager. 44 if (item->GetState() != content::DownloadItem::IN_PROGRESS) 45 return; 46 47 // GET downloads without authentication are delegated to the Android 48 // DownloadManager. Chrome is responsible for the rest. See 49 // InterceptDownloadResourceThrottle::ProcessDownloadRequest(). 50 content::DownloadControllerAndroid::Get()->OnDownloadStarted(item); 51 } 52 53 #else // OS_ANDROID 54 55 class DefaultUIControllerDelegate : public DownloadUIController::Delegate { 56 public: 57 // |profile| is required to outlive DefaultUIControllerDelegate. 58 explicit DefaultUIControllerDelegate(Profile* profile) 59 : profile_(profile) {} 60 virtual ~DefaultUIControllerDelegate() {} 61 62 private: 63 // DownloadUIController::Delegate 64 virtual void OnNewDownloadReady(content::DownloadItem* item) OVERRIDE; 65 66 Profile* profile_; 67 }; 68 69 void DefaultUIControllerDelegate::OnNewDownloadReady( 70 content::DownloadItem* item) { 71 content::WebContents* web_contents = item->GetWebContents(); 72 Browser* browser = 73 web_contents ? chrome::FindBrowserWithWebContents(web_contents) : NULL; 74 75 // As a last resort, use the last active browser for this profile. Not ideal, 76 // but better than not showing the download at all. 77 if (browser == NULL) { 78 browser = chrome::FindLastActiveWithProfile(profile_, 79 chrome::GetActiveDesktop()); 80 } 81 82 if (browser) 83 browser->ShowDownload(item); 84 } 85 86 #endif // !OS_ANDROID 87 88 } // namespace 89 90 DownloadUIController::Delegate::~Delegate() { 91 } 92 93 DownloadUIController::DownloadUIController(content::DownloadManager* manager, 94 scoped_ptr<Delegate> delegate) 95 : download_notifier_(manager, this), 96 delegate_(delegate.Pass()) { 97 if (!delegate_) { 98 #if defined(OS_ANDROID) 99 delegate_.reset(new DefaultUIControllerDelegateAndroid()); 100 #else 101 // The delegate should not be invoked after the profile has gone away. This 102 // should be the case since DownloadUIController is owned by 103 // DownloadService, which in turn is a profile keyed service. 104 delegate_.reset(new DefaultUIControllerDelegate( 105 Profile::FromBrowserContext(manager->GetBrowserContext()))); 106 #endif 107 } 108 } 109 110 DownloadUIController::~DownloadUIController() { 111 } 112 113 void DownloadUIController::OnDownloadCreated(content::DownloadManager* manager, 114 content::DownloadItem* item) { 115 // SavePackage downloads are created in a state where they can be shown in the 116 // browser. Call OnDownloadUpdated() once to notify the UI immediately. 117 OnDownloadUpdated(manager, item); 118 } 119 120 void DownloadUIController::OnDownloadUpdated(content::DownloadManager* manager, 121 content::DownloadItem* item) { 122 DownloadItemModel item_model(item); 123 124 // Ignore if we've already notified the UI about |item| or if it isn't a new 125 // download. 126 if (item_model.WasUINotified() || !item_model.ShouldNotifyUI()) 127 return; 128 129 // Wait until the target path is determined. 130 if (item->GetTargetFilePath().empty()) 131 return; 132 133 DownloadItemModel(item).SetWasUINotified(true); 134 delegate_->OnNewDownloadReady(item); 135 } 136