blob: 2bfb09353fbe589a600ebf33702583bca367fc93 [file] [log] [blame]
[email protected]b3756012013-03-06 17:43:021// 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
Peter Boström924f8032021-04-02 20:36:027#include <memory>
dchenge73d8520c2015-12-27 01:19:098#include <utility>
9
[email protected]9dd188f2014-05-15 18:35:2010#include "base/callback.h"
Keishi Hattori0e45c022021-11-27 09:25:5211#include "base/memory/raw_ptr.h"
Christopher Thompsoncaf69fe2018-03-06 18:33:0112#include "base/metrics/histogram_macros.h"
avie4d7b6f2015-12-26 00:59:1813#include "build/build_config.h"
James Cook27fdaae2020-11-13 23:33:3114#include "build/chromeos_buildflags.h"
pfeldman03485942016-03-29 19:51:0415#include "chrome/browser/devtools/devtools_window.h"
[email protected]b3756012013-03-06 17:43:0216#include "chrome/browser/download/download_item_model.h"
yoshiki09481b72015-07-17 03:12:3817#include "chrome/browser/download/download_shelf.h"
Side Yilmazcdf366dc2021-02-26 09:39:5618#include "chrome/browser/download/download_stats.h"
Christopher Thompsoncaf69fe2018-03-06 18:33:0119#include "chrome/browser/ssl/security_state_tab_helper.h"
Min Qina9f487872018-02-09 20:43:2320#include "components/download/public/common/download_item.h"
Christopher Thompsoncaf69fe2018-03-06 18:33:0121#include "components/security_state/core/security_state.h"
Min Qina9f487872018-02-09 20:43:2322#include "content/public/browser/download_item_utils.h"
[email protected]b3756012013-03-06 17:43:0223#include "content/public/browser/web_contents.h"
24#include "content/public/browser/web_contents_delegate.h"
25
Xiaohan Wangab5fb912022-01-12 19:21:4826#if BUILDFLAG(IS_ANDROID)
Min Qin0b80a0372019-12-18 03:20:5027#include "chrome/browser/download/android/download_controller.h"
Min Qin869874062019-10-15 19:27:5628#include "chrome/browser/download/android/download_controller_base.h"
[email protected]b3756012013-03-06 17:43:0229#else
30#include "chrome/browser/profiles/profile.h"
dbeam2faad5a2015-03-02 22:49:2531#include "chrome/browser/ui/browser_finder.h"
Collin Baker8a217552019-05-29 19:47:5132#include "chrome/browser/ui/browser_tabstrip.h"
33#include "chrome/browser/ui/browser_window.h"
34#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]b3756012013-03-06 17:43:0235#endif
36
Xiaohan Wangab5fb912022-01-12 19:21:4837#if BUILDFLAG(IS_CHROMEOS)
estade7fc53a32015-09-29 19:44:1938#include "chrome/browser/download/notification/download_notification_manager.h"
Xiaohan Wangab5fb912022-01-12 19:21:4839#endif // BUILDFLAG(IS_CHROMEOS)
estade7fc53a32015-09-29 19:44:1940
[email protected]b3756012013-03-06 17:43:0241namespace {
42
yoshikif42d8fc2015-03-04 20:07:5043// DownloadShelfUIControllerDelegate{Android,} is used when a
44// DownloadUIController is
[email protected]b3756012013-03-06 17:43:0245// constructed without specifying an explicit Delegate.
Xiaohan Wangab5fb912022-01-12 19:21:4846#if BUILDFLAG(IS_ANDROID)
[email protected]b3756012013-03-06 17:43:0247
yoshikif42d8fc2015-03-04 20:07:5048class AndroidUIControllerDelegate : public DownloadUIController::Delegate {
[email protected]b3756012013-03-06 17:43:0249 public:
yoshikif42d8fc2015-03-04 20:07:5050 AndroidUIControllerDelegate() {}
51 ~AndroidUIControllerDelegate() override {}
[email protected]b3756012013-03-06 17:43:0252
53 private:
54 // DownloadUIController::Delegate
Min Qina9f487872018-02-09 20:43:2355 void OnNewDownloadReady(download::DownloadItem* item) override;
[email protected]b3756012013-03-06 17:43:0256};
57
yoshikif42d8fc2015-03-04 20:07:5058void AndroidUIControllerDelegate::OnNewDownloadReady(
Min Qina9f487872018-02-09 20:43:2359 download::DownloadItem* item) {
jinsukkim3da95ee02016-06-21 22:34:4660 DownloadControllerBase::Get()->OnDownloadStarted(item);
[email protected]b3756012013-03-06 17:43:0261}
62
Xiaohan Wang411793762022-01-17 20:23:1563#else // BUILDFLAG(IS_ANDROID)
[email protected]b3756012013-03-06 17:43:0264
yoshikif42d8fc2015-03-04 20:07:5065class DownloadShelfUIControllerDelegate
66 : public DownloadUIController::Delegate {
[email protected]b3756012013-03-06 17:43:0267 public:
yoshikif42d8fc2015-03-04 20:07:5068 // |profile| is required to outlive DownloadShelfUIControllerDelegate.
69 explicit DownloadShelfUIControllerDelegate(Profile* profile)
[email protected]b3756012013-03-06 17:43:0270 : profile_(profile) {}
yoshikif42d8fc2015-03-04 20:07:5071 ~DownloadShelfUIControllerDelegate() override {}
[email protected]b3756012013-03-06 17:43:0272
73 private:
74 // DownloadUIController::Delegate
Min Qina9f487872018-02-09 20:43:2375 void OnNewDownloadReady(download::DownloadItem* item) override;
[email protected]b3756012013-03-06 17:43:0276
Keishi Hattori0e45c022021-11-27 09:25:5277 raw_ptr<Profile> profile_;
[email protected]b3756012013-03-06 17:43:0278};
79
yoshikif42d8fc2015-03-04 20:07:5080void DownloadShelfUIControllerDelegate::OnNewDownloadReady(
Min Qina9f487872018-02-09 20:43:2381 download::DownloadItem* item) {
82 content::WebContents* web_contents =
83 content::DownloadItemUtils::GetWebContents(item);
pfeldman03485942016-03-29 19:51:0484 // For the case of DevTools web contents, we'd like to use target browser
85 // shelf although saving from the DevTools web contents.
86 if (web_contents && DevToolsWindow::IsDevToolsWindow(web_contents)) {
87 DevToolsWindow* devtools_window =
88 DevToolsWindow::AsDevToolsWindow(web_contents);
89 content::WebContents* inspected =
90 devtools_window->GetInspectedWebContents();
91 // Do not overwrite web contents for the case of remote debugging.
92 if (inspected)
93 web_contents = inspected;
94 }
[email protected]b3756012013-03-06 17:43:0295 Browser* browser =
96 web_contents ? chrome::FindBrowserWithWebContents(web_contents) : NULL;
97
98 // As a last resort, use the last active browser for this profile. Not ideal,
99 // but better than not showing the download at all.
scottmg5c03fe022016-02-03 01:27:24100 if (browser == nullptr)
101 browser = chrome::FindLastActiveWithProfile(profile_);
[email protected]b3756012013-03-06 17:43:02102
yoshiki09481b72015-07-17 03:12:38103 if (browser && browser->window() &&
104 DownloadItemModel(item).ShouldShowInShelf()) {
Shakti Sahuceb08fb2018-09-27 23:56:28105 DownloadUIModel::DownloadUIModelPtr model = DownloadItemModel::Wrap(item);
106
yoshiki09481b72015-07-17 03:12:38107 // GetDownloadShelf creates the download shelf if it was not yet created.
Shakti Sahuceb08fb2018-09-27 23:56:28108 browser->window()->GetDownloadShelf()->AddDownload(std::move(model));
yoshiki09481b72015-07-17 03:12:38109 }
[email protected]b3756012013-03-06 17:43:02110}
111
Xiaohan Wang411793762022-01-17 20:23:15112#endif // BUILDFLAG(IS_ANDROID)
[email protected]b3756012013-03-06 17:43:02113
114} // namespace
115
116DownloadUIController::Delegate::~Delegate() {
117}
118
Shakti Sahuff9ee2b62019-09-16 23:28:59119DownloadUIController::DownloadUIController(content::DownloadManager* manager,
120 std::unique_ptr<Delegate> delegate)
121 : download_notifier_(manager, this), delegate_(std::move(delegate)) {
Xiaohan Wangab5fb912022-01-12 19:21:48122#if BUILDFLAG(IS_ANDROID)
estade7fc53a32015-09-29 19:44:19123 if (!delegate_)
Peter Boström08e7ed82021-04-19 17:49:59124 delegate_ = std::make_unique<AndroidUIControllerDelegate>();
Xiaohan Wangab5fb912022-01-12 19:21:48125#elif BUILDFLAG(IS_CHROMEOS)
estade889fbece2016-08-08 23:20:22126 if (!delegate_) {
estade7fc53a32015-09-29 19:44:19127 // The Profile is guaranteed to be valid since DownloadUIController is owned
128 // by DownloadService, which in turn is a profile keyed service.
Peter Boström6b701822021-04-15 03:53:08129 delegate_ = std::make_unique<DownloadNotificationManager>(
130 Profile::FromBrowserContext(manager->GetBrowserContext()));
[email protected]b3756012013-03-06 17:43:02131 }
Xiaohan Wangab5fb912022-01-12 19:21:48132#else // BUILDFLAG(IS_CHROMEOS)
estade7fc53a32015-09-29 19:44:19133 if (!delegate_) {
Peter Boström924f8032021-04-02 20:36:02134 delegate_ = std::make_unique<DownloadShelfUIControllerDelegate>(
135 Profile::FromBrowserContext(manager->GetBrowserContext()));
estade7fc53a32015-09-29 19:44:19136 }
Xiaohan Wangab5fb912022-01-12 19:21:48137#endif // BUILDFLAG(IS_ANDROID)
[email protected]b3756012013-03-06 17:43:02138}
139
140DownloadUIController::~DownloadUIController() {
141}
142
143void DownloadUIController::OnDownloadCreated(content::DownloadManager* manager,
Min Qina9f487872018-02-09 20:43:23144 download::DownloadItem* item) {
Christopher Thompsoncaf69fe2018-03-06 18:33:01145 // Record the security level of the page triggering the download. Only record
146 // when the download occurs in the WebContents that initiated the download
147 // (e.g., not downloads in new tabs or windows, which have a different
148 // WebContents).
149 content::WebContents* web_contents =
150 content::DownloadItemUtils::GetWebContents(item);
151 if (web_contents && (item->IsSavePackageDownload() ||
Jochen Eisinger7678c8ac2018-05-07 15:47:34152 (web_contents->GetURL() != item->GetOriginalUrl() &&
Christopher Thompsoncaf69fe2018-03-06 18:33:01153 web_contents->GetURL() != item->GetURL()))) {
154 auto* security_state_tab_helper =
155 SecurityStateTabHelper::FromWebContents(web_contents);
156 if (security_state_tab_helper) {
Christopher Thompsoncaf69fe2018-03-06 18:33:01157 UMA_HISTOGRAM_ENUMERATION("Security.SecurityLevel.DownloadStarted",
Emily Stark0e6b93ad2019-03-11 17:27:30158 security_state_tab_helper->GetSecurityLevel(),
Christopher Thompsoncaf69fe2018-03-06 18:33:01159 security_state::SECURITY_LEVEL_COUNT);
Emily Starkca844c02019-08-28 04:28:44160 UMA_HISTOGRAM_ENUMERATION(
161 "Security.SafetyTips.DownloadStarted",
162 security_state_tab_helper->GetVisibleSecurityState()
meacerb66107d2019-10-17 20:00:19163 ->safety_tip_info.status);
Christopher Thompsoncaf69fe2018-03-06 18:33:01164 }
165 }
166
Side Yilmazcdf366dc2021-02-26 09:39:56167 if (web_contents) {
168 // TODO(crbug.com/1179196): Add test for this metric.
169 RecordDownloadStartPerProfileType(
170 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
171 }
172
[email protected]b3756012013-03-06 17:43:02173 // SavePackage downloads are created in a state where they can be shown in the
174 // browser. Call OnDownloadUpdated() once to notify the UI immediately.
175 OnDownloadUpdated(manager, item);
176}
177
178void DownloadUIController::OnDownloadUpdated(content::DownloadManager* manager,
Min Qina9f487872018-02-09 20:43:23179 download::DownloadItem* item) {
[email protected]9dd188f2014-05-15 18:35:20180 DownloadItemModel item_model(item);
181
[email protected]b3756012013-03-06 17:43:02182 // Ignore if we've already notified the UI about |item| or if it isn't a new
183 // download.
[email protected]9dd188f2014-05-15 18:35:20184 if (item_model.WasUINotified() || !item_model.ShouldNotifyUI())
[email protected]b3756012013-03-06 17:43:02185 return;
186
Owen Minf98b57e52021-09-30 23:14:15187 // Downloads blocked by local policies should be notified, otherwise users
188 // won't get any feedback that the download has failed.
189 bool should_notify =
190 item->GetLastReason() ==
191 download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED &&
192 item->GetMixedContentStatus() !=
193 download::DownloadItem::MixedContentStatus::SILENT_BLOCK;
194
hichris1233032fbd2015-10-12 20:37:28195 // Wait until the target path is determined or the download is canceled.
196 if (item->GetTargetFilePath().empty() &&
Owen Minf98b57e52021-09-30 23:14:15197 item->GetState() != download::DownloadItem::CANCELLED && !should_notify) {
[email protected]b3756012013-03-06 17:43:02198 return;
Owen Minf98b57e52021-09-30 23:14:15199 }
[email protected]b3756012013-03-06 17:43:02200
Min Qina9f487872018-02-09 20:43:23201 content::WebContents* web_contents =
202 content::DownloadItemUtils::GetWebContents(item);
yoshiki09481b72015-07-17 03:12:38203 if (web_contents) {
Xiaohan Wangab5fb912022-01-12 19:21:48204#if BUILDFLAG(IS_ANDROID)
Min Qinc55efe52021-04-15 05:26:54205 DownloadController::CloseTabIfEmpty(web_contents, item);
Min Qin0b80a0372019-12-18 03:20:50206#else
yoshiki09481b72015-07-17 03:12:38207 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
208 // If the download occurs in a new tab, and it's not a save page
209 // download (started before initial navigation completed) close it.
210 // Avoid calling CloseContents if the tab is not in this browser's tab strip
211 // model; this can happen if the download was initiated by something
212 // internal to Chrome, such as by the app list.
213 if (browser && web_contents->GetController().IsInitialNavigation() &&
214 browser->tab_strip_model()->count() > 1 &&
215 browser->tab_strip_model()->GetIndexOfWebContents(web_contents) !=
216 TabStripModel::kNoTab &&
217 !item->IsSavePackageDownload()) {
218 web_contents->Close();
219 }
Xiaohan Wangab5fb912022-01-12 19:21:48220#endif // BUILDFLAG(IS_ANDROID)
yoshiki09481b72015-07-17 03:12:38221 }
yoshiki09481b72015-07-17 03:12:38222
Min Qina9f487872018-02-09 20:43:23223 if (item->GetState() == download::DownloadItem::CANCELLED)
hichris1233032fbd2015-10-12 20:37:28224 return;
225
226 DownloadItemModel(item).SetWasUINotified(true);
[email protected]9dd188f2014-05-15 18:35:20227 delegate_->OnNewDownloadReady(item);
[email protected]b3756012013-03-06 17:43:02228}