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