Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / download / notification / download_group_notification.cc
bloba6a9a295455b7c0031a96da3a89d31d7a942e55e
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"
7 #include <algorithm>
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_crx_util.h"
13 #include "chrome/browser/download/download_item_model.h"
14 #include "chrome/browser/notifications/profile_notification.h"
15 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
16 #include "chrome/common/url_constants.h"
17 #include "chrome/grit/chromium_strings.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "content/public/browser/download_item.h"
20 #include "grit/theme_resources.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/l10n/time_format.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/gfx/text_elider.h"
25 #include "ui/message_center/message_center_impl.h"
26 #include "ui/views/controls/label.h"
28 namespace {
30 const char kDownloadNotificationNotifierId[] =
31 "chrome://downloads/notification/id-notifier";
33 const size_t kMaxFilenameWidth = 160; // in px
35 base::string16 GetStatusString(content::DownloadItem* download) {
36 switch (download->GetState()) {
37 case content::DownloadItem::IN_PROGRESS:
38 // "Adding to Chrome..."
39 if (download->AllDataSaved() &&
40 download_crx_util::IsExtensionDownload(*download)) {
41 return l10n_util::GetStringUTF16(
42 IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING);
45 // "Paused"
46 if (download->IsPaused())
47 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
49 // "100/120 MB" or "100 MB"
50 if (download->GetReceivedBytes() > 0) {
51 DownloadItemModel model(download);
52 return model.GetProgressSizesString();
55 // "Starting..."
56 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING);
57 case content::DownloadItem::COMPLETE:
58 // "Removed" or "Completed"
59 if (download->GetFileExternallyRemoved())
60 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED);
61 else
62 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_COMPLETED);
63 case content::DownloadItem::CANCELLED:
64 // "Cancelled"
65 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
66 case content::DownloadItem::INTERRUPTED: {
67 content::DownloadInterruptReason reason = download->GetLastReason();
68 if (reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
69 // "Failed - <REASON>"
70 DownloadItemModel model(download);
71 base::string16 interrupt_reason = model.GetInterruptReasonText();
72 return l10n_util::GetStringFUTF16(
73 IDS_DOWNLOAD_STATUS_INTERRUPTED, interrupt_reason);
76 // Same as DownloadItem::CANCELLED.
77 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
79 case content::DownloadItem::MAX_DOWNLOAD_STATE:
80 break;
83 NOTREACHED();
84 return base::string16();
87 } // anonymous namespace
89 // static
90 base::string16 DownloadGroupNotification::TruncateFileName(
91 const content::DownloadItem* download) {
92 return gfx::ElideFilename(download->GetFileNameToReportUser(),
93 views::Label().font_list(),
94 kMaxFilenameWidth);
97 DownloadGroupNotification::DownloadGroupNotification(
98 Profile* profile, DownloadNotificationManagerForProfile* manager)
99 : profile_(profile) {
101 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
103 message_center::RichNotificationData data;
104 // Creates the notification instance. |title| and |body| will be overridden
105 // by UpdateNotificationData() below.
106 notification_.reset(new Notification(
107 message_center::NOTIFICATION_TYPE_MULTIPLE,
108 base::string16(), // title
109 base::string16(), // body
110 bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING),
111 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
112 kDownloadNotificationNotifierId),
113 base::string16(), // display_source
114 GURL(kDownloadNotificationOrigin), // origin_url
115 "GROUP", // tag
116 data, watcher()));
118 notification_->SetSystemPriority();
119 notification_->set_never_timeout(false);
121 std::vector<message_center::ButtonInfo> notification_actions;
122 message_center::ButtonInfo button_info =
123 message_center::ButtonInfo(l10n_util::GetStringUTF16(
124 IDS_DOWNLOAD_LINK_SHOW_ALL_DOWNLOADS));
125 notification_actions.push_back(button_info);
126 notification_->set_buttons(notification_actions);
129 DownloadGroupNotification::~DownloadGroupNotification() {}
131 bool DownloadGroupNotification::IsPopup() const {
132 const ProfileID profile_id =
133 NotificationUIManager::GetProfileID(profile_);
134 const std::string& notification_id = GetNotificationId();
135 const std::string& raw_notification_id = g_browser_process->
136 notification_ui_manager()->FindById(notification_id, profile_id)->id();
137 auto popup_notifications =
138 g_browser_process->message_center()->GetPopupNotifications();
139 for (auto notification : popup_notifications) {
140 if (notification->id() == raw_notification_id)
141 return true;
143 return false;
146 void DownloadGroupNotification::OnDownloadUpdated(
147 content::DownloadItem* download) {
148 if (items_.find(download) != items_.end()) {
149 Update();
153 void DownloadGroupNotification::OnDownloadAdded(
154 content::DownloadItem* download) {
155 if (items_.find(download) == items_.end()) {
156 items_.insert(download);
157 int inprogress_download_count = 0;
158 // If new download is started and there are more than 2 downloads in total,
159 // show the group notification.
160 for (auto it = items_.begin(); it != items_.end(); it++) {
161 if (!(*it)->IsDone() && ++inprogress_download_count >= 2) {
162 Show();
163 break;
169 void DownloadGroupNotification::OnDownloadRemoved(
170 content::DownloadItem* download) {
171 // The given |download| may be already free'd.
172 if (items_.find(download) != items_.end()) {
173 items_.erase(download);
174 truncated_filename_cache_.erase(download);
175 if (items_.size() <= 1)
176 Hide();
180 void DownloadGroupNotification::OnNotificationClose() {
181 visible_ = false;
183 // When the notification is closed, removes the finished downloads.
184 auto it = items_.begin();
185 while (it != items_.end()) {
186 if ((*it)->GetState() != content::DownloadItem::IN_PROGRESS)
187 items_.erase(*(it++));
188 else
189 it++;
193 void DownloadGroupNotification::OnNotificationClick() {
194 OpenDownloads();
197 void DownloadGroupNotification::OnNotificationButtonClick(
198 int button_index) {
199 DCHECK_EQ(0, button_index);
200 OpenDownloads();
203 void DownloadGroupNotification::Hide() {
204 hide_next_ = true;
205 Update();
208 void DownloadGroupNotification::Show() {
209 show_next_ = true;
210 Update();
213 void DownloadGroupNotification::Update() {
214 if (visible_) {
215 const ProfileID profile_id =
216 NotificationUIManager::GetProfileID(profile_);
217 const std::string& notification_id = GetNotificationId();
218 if (hide_next_) {
219 g_browser_process->notification_ui_manager()->
220 CancelById(notification_id, profile_id);
221 visible_ = false;
222 } else {
223 UpdateNotificationData();
224 g_browser_process->notification_ui_manager()->
225 Update(*notification_, profile_);
227 const std::string notification_id_in_message_center =
228 ProfileNotification::GetProfileNotificationId(notification_id,
229 profile_id);
231 auto message_center = g_browser_process->message_center();
232 // TODO(yoshiki): Remove this once in-place updating of notification is
233 // bug free.
234 InvokeUnsafeForceNotificationFlush(
235 message_center, notification_id_in_message_center);
237 } else {
238 if (show_next_) {
239 UpdateNotificationData();
240 g_browser_process->notification_ui_manager()->
241 Add(*notification_, profile_);
242 visible_ = true;
245 show_next_ = false;
246 hide_next_ = false;
249 void DownloadGroupNotification::UpdateNotificationData() {
250 bool all_finished = true;
251 std::vector<message_center::NotificationItem> subitems;
252 for (auto download : items_) {
253 DownloadItemModel model(download);
254 auto it = truncated_filename_cache_.find(download);
255 auto original_filename = download->GetFileNameToReportUser();
256 if (it == truncated_filename_cache_.end() ||
257 it->second.truncated_filename.empty() ||
258 it->second.original_filename != original_filename) {
259 truncated_filename_cache_[download].original_filename = original_filename;
260 truncated_filename_cache_[download].truncated_filename =
261 TruncateFileName(download);
264 // TODO(yoshiki): Use emplace_back when C++11 becomes allowed.
265 subitems.push_back(message_center::NotificationItem(
266 truncated_filename_cache_[download].truncated_filename,
267 GetStatusString(download)));
269 if (!download->IsDone())
270 all_finished = false;
272 notification_->set_items(subitems);
274 int title_id = all_finished ? IDS_DOWNLOAD_STATUS_GROUP_DONE_TITLE :
275 IDS_DOWNLOAD_STATUS_GROUP_IN_PROGRESS_TITLE;
276 notification_->set_title(l10n_util::GetPluralStringFUTF16(
277 title_id, items_.size()));
280 std::string DownloadGroupNotification::GetNotificationId() const {
281 return "GROUP";
284 void DownloadGroupNotification::OpenDownloads() {
285 chrome::ScopedTabbedBrowserDisplayer browser_displayer(
286 profile_, chrome::GetActiveDesktop());
287 Browser* browser = browser_displayer.browser();
288 DCHECK(browser);
290 browser->OpenURL(content::OpenURLParams(
291 GURL(chrome::kChromeUIDownloadsURL), content::Referrer(),
292 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
293 false /* is_renderer_initiated */));