1 // Copyright 2015 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/notification/download_group_notification.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/download/download_item_model.h"
13 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
14 #include "chrome/common/url_constants.h"
15 #include "chrome/grit/chromium_strings.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "content/public/browser/download_item.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/l10n/time_format.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/gfx/text_elider.h"
23 #include "ui/views/controls/label.h"
27 const char kDownloadNotificationNotifierId
[] =
28 "chrome://downloads/notification/id-notifier";
30 const size_t kMaxFilenameWidth
= 160; // in px
32 base::string16
TruncateFilename(const base::FilePath
& filename
) {
33 return gfx::ElideFilename(filename
,
34 views::Label().font_list(),
38 } // anonymous namespace
40 DownloadGroupNotification::DownloadGroupNotification(
41 Profile
* profile
, DownloadNotificationManagerForProfile
* manager
)
44 ui::ResourceBundle
& bundle
= ui::ResourceBundle::GetSharedInstance();
46 message_center::RichNotificationData data
;
47 // Creates the notification instance. |title| and |body| will be overridden
48 // by UpdateNotificationData() below.
49 notification_
.reset(new Notification(
50 message_center::NOTIFICATION_TYPE_MULTIPLE
,
51 GURL(kDownloadNotificationOrigin
), // origin_url
52 base::string16(), // title
53 base::string16(), // body
54 bundle
.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING
),
55 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT
,
56 kDownloadNotificationNotifierId
),
57 base::string16(), // display_source
61 notification_
->SetSystemPriority();
62 notification_
->set_never_timeout(false);
64 std::vector
<message_center::ButtonInfo
> notification_actions
;
65 message_center::ButtonInfo button_info
=
66 message_center::ButtonInfo(l10n_util::GetStringUTF16(
67 IDS_DOWNLOAD_LINK_SHOW_ALL_DOWNLOADS
));
68 notification_actions
.push_back(button_info
);
69 notification_
->set_buttons(notification_actions
);
72 DownloadGroupNotification::~DownloadGroupNotification() {}
74 bool DownloadGroupNotification::IsPopup() const {
75 const ProfileID profile_id
=
76 NotificationUIManager::GetProfileID(profile_
);
77 const std::string
& notification_id
= GetNotificationId();
78 const std::string
& raw_notification_id
= g_browser_process
->
79 notification_ui_manager()->FindById(notification_id
, profile_id
)->id();
80 auto popup_notifications
=
81 g_browser_process
->message_center()->GetPopupNotifications();
82 for (auto notification
: popup_notifications
) {
83 if (notification
->id() == raw_notification_id
)
89 void DownloadGroupNotification::OnDownloadUpdated(
90 content::DownloadItem
* download
) {
91 if (items_
.find(download
) != items_
.end()) {
96 void DownloadGroupNotification::OnDownloadAdded(
97 content::DownloadItem
* download
) {
98 if (items_
.find(download
) == items_
.end()) {
99 items_
.insert(download
);
100 int inprogress_download_count
= 0;
101 // If new download is started and there are more than 2 downloads in total,
102 // show the group notification.
103 for (auto it
= items_
.begin(); it
!= items_
.end(); it
++) {
104 if (!(*it
)->IsDone() && ++inprogress_download_count
>= 2) {
112 void DownloadGroupNotification::OnDownloadRemoved(
113 content::DownloadItem
* download
) {
114 // The given |download| may be already free'd.
115 if (items_
.find(download
) != items_
.end()) {
116 items_
.erase(download
);
117 if (items_
.size() <= 1)
122 void DownloadGroupNotification::OnNotificationClose() {
125 // When the notification is closed, removes the finished downloads.
126 auto it
= items_
.begin();
127 while (it
!= items_
.end()) {
128 if ((*it
)->GetState() != content::DownloadItem::IN_PROGRESS
)
129 items_
.erase(*(it
++));
135 void DownloadGroupNotification::OnNotificationClick() {
139 void DownloadGroupNotification::OnNotificationButtonClick(
141 DCHECK_EQ(0, button_index
);
145 void DownloadGroupNotification::Hide() {
150 void DownloadGroupNotification::Show() {
155 void DownloadGroupNotification::Update() {
158 const ProfileID profile_id
=
159 NotificationUIManager::GetProfileID(profile_
);
160 const std::string
& notification_id
= GetNotificationId();
161 g_browser_process
->notification_ui_manager()->
162 CancelById(notification_id
, profile_id
);
165 UpdateNotificationData();
166 g_browser_process
->notification_ui_manager()->
167 Update(*notification_
, profile_
);
171 UpdateNotificationData();
172 g_browser_process
->notification_ui_manager()->
173 Add(*notification_
, profile_
);
181 void DownloadGroupNotification::UpdateNotificationData() {
182 bool all_finished
= true;
183 std::vector
<message_center::NotificationItem
> subitems
;
184 for (auto download
: items_
) {
185 DownloadItemModel
model(download
);
186 // TODO(yoshiki): Use emplace_back when C++11 becomes allowed.
187 subitems
.push_back(message_center::NotificationItem(
188 TruncateFilename(download
->GetFileNameToReportUser()),
189 model
.GetStatusText()));
191 if (!download
->IsDone())
192 all_finished
= false;
194 notification_
->set_items(subitems
);
196 int title_id
= all_finished
? IDS_DOWNLOAD_STATUS_GROUP_DONE_TITLE
:
197 IDS_DOWNLOAD_STATUS_GROUP_IN_PROGRESS_TITLE
;
198 notification_
->set_title(l10n_util::GetPluralStringFUTF16(
199 title_id
, items_
.size()));
202 std::string
DownloadGroupNotification::GetNotificationId() const {
206 void DownloadGroupNotification::OpenDownloads() {
207 chrome::ScopedTabbedBrowserDisplayer
browser_displayer(
208 profile_
, chrome::GetActiveDesktop());
209 Browser
* browser
= browser_displayer
.browser();
212 browser
->OpenURL(content::OpenURLParams(
213 GURL(chrome::kChromeUIDownloadsURL
), content::Referrer(),
214 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_LINK
,
215 false /* is_renderer_initiated */));