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.
5 #include "chrome/browser/download/download_ui_controller.h"
7 #include "base/callback.h"
8 #include "base/stl_util.h"
9 #include "chrome/browser/download/download_item_model.h"
10 #include "chrome/browser/download/download_shelf.h"
11 #include "chrome/browser/ui/browser_finder.h"
12 #include "chrome/browser/ui/browser_tabstrip.h"
13 #include "chrome/browser/ui/browser_window.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "content/public/browser/download_item.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_delegate.h"
19 #if defined(OS_ANDROID)
20 #include "content/public/browser/android/download_controller_android.h"
22 #include "chrome/browser/download/notification/download_notification_manager.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/browser_finder.h"
25 #include "chrome/browser/ui/host_desktop.h"
30 // DownloadShelfUIControllerDelegate{Android,} is used when a
31 // DownloadUIController is
32 // constructed without specifying an explicit Delegate.
33 #if defined(OS_ANDROID)
35 class AndroidUIControllerDelegate
: public DownloadUIController::Delegate
{
37 AndroidUIControllerDelegate() {}
38 ~AndroidUIControllerDelegate() override
{}
41 // DownloadUIController::Delegate
42 void OnNewDownloadReady(content::DownloadItem
* item
) override
;
45 void AndroidUIControllerDelegate::OnNewDownloadReady(
46 content::DownloadItem
* item
) {
47 // The Android DownloadController is only interested in IN_PROGRESS downloads.
48 // Ones which are INTERRUPTED etc. can't be handed over to the Android
50 if (item
->GetState() != content::DownloadItem::IN_PROGRESS
)
53 // GET downloads without authentication are delegated to the Android
54 // DownloadManager. Chrome is responsible for the rest. See
55 // InterceptDownloadResourceThrottle::ProcessDownloadRequest().
56 content::DownloadControllerAndroid::Get()->OnDownloadStarted(item
);
61 class DownloadShelfUIControllerDelegate
62 : public DownloadUIController::Delegate
{
64 // |profile| is required to outlive DownloadShelfUIControllerDelegate.
65 explicit DownloadShelfUIControllerDelegate(Profile
* profile
)
66 : profile_(profile
) {}
67 ~DownloadShelfUIControllerDelegate() override
{}
70 // DownloadUIController::Delegate
71 void OnNewDownloadReady(content::DownloadItem
* item
) override
;
76 void DownloadShelfUIControllerDelegate::OnNewDownloadReady(
77 content::DownloadItem
* item
) {
78 content::WebContents
* web_contents
= item
->GetWebContents();
80 web_contents
? chrome::FindBrowserWithWebContents(web_contents
) : NULL
;
82 // As a last resort, use the last active browser for this profile. Not ideal,
83 // but better than not showing the download at all.
84 if (browser
== NULL
) {
85 browser
= chrome::FindLastActiveWithProfile(profile_
,
86 chrome::GetActiveDesktop());
89 if (browser
&& browser
->window() &&
90 DownloadItemModel(item
).ShouldShowInShelf()) {
91 // GetDownloadShelf creates the download shelf if it was not yet created.
92 browser
->window()->GetDownloadShelf()->AddDownload(item
);
100 DownloadUIController::Delegate::~Delegate() {
103 DownloadUIController::DownloadUIController(content::DownloadManager
* manager
,
104 scoped_ptr
<Delegate
> delegate
)
105 : download_notifier_(manager
, this),
106 delegate_(delegate
.Pass()) {
108 #if defined(OS_ANDROID)
109 delegate_
.reset(new AndroidUIControllerDelegate());
111 // The delegate should not be invoked after the profile has gone away. This
112 // should be the case since DownloadUIController is owned by
113 // DownloadService, which in turn is a profile keyed service.
114 if (DownloadNotificationManager::IsEnabled()) {
115 delegate_
.reset(new DownloadNotificationManager(
116 Profile::FromBrowserContext(manager
->GetBrowserContext())));
118 delegate_
.reset(new DownloadShelfUIControllerDelegate(
119 Profile::FromBrowserContext(manager
->GetBrowserContext())));
125 DownloadUIController::~DownloadUIController() {
128 void DownloadUIController::OnDownloadCreated(content::DownloadManager
* manager
,
129 content::DownloadItem
* item
) {
130 // SavePackage downloads are created in a state where they can be shown in the
131 // browser. Call OnDownloadUpdated() once to notify the UI immediately.
132 OnDownloadUpdated(manager
, item
);
135 void DownloadUIController::OnDownloadUpdated(content::DownloadManager
* manager
,
136 content::DownloadItem
* item
) {
137 DownloadItemModel
item_model(item
);
139 // Ignore if we've already notified the UI about |item| or if it isn't a new
141 if (item_model
.WasUINotified() || !item_model
.ShouldNotifyUI())
144 // Wait until the target path is determined.
145 if (item
->GetTargetFilePath().empty())
148 DownloadItemModel(item
).SetWasUINotified(true);
150 #if !defined(OS_ANDROID)
151 content::WebContents
* web_contents
= item
->GetWebContents();
153 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents
);
154 // If the download occurs in a new tab, and it's not a save page
155 // download (started before initial navigation completed) close it.
156 // Avoid calling CloseContents if the tab is not in this browser's tab strip
157 // model; this can happen if the download was initiated by something
158 // internal to Chrome, such as by the app list.
159 if (browser
&& web_contents
->GetController().IsInitialNavigation() &&
160 browser
->tab_strip_model()->count() > 1 &&
161 browser
->tab_strip_model()->GetIndexOfWebContents(web_contents
) !=
162 TabStripModel::kNoTab
&&
163 !item
->IsSavePackageDownload()) {
164 web_contents
->Close();
169 delegate_
->OnNewDownloadReady(item
);