Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(531)

Side by Side Diff: chrome/browser/download/notification/download_notification_item.cc

Issue 852043002: Initial Implementation of Download Notification (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Minor bug fix. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/download/notification/download_notification_item.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "chrome/browser/download/download_crx_util.h"
9 #include "chrome/browser/download/download_item_model.h"
10 #include "chrome/grit/chromium_strings.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/download_item.h"
15 #include "content/public/browser/web_contents.h"
16 #include "grit/theme_resources.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/message_center/message_center.h"
20 #include "ui/message_center/notification.h"
21 #include "ui/message_center/notification_delegate.h"
22
23 using message_center::Notification;
24
25 namespace {
26
27 const char kDownloadNotificationNotifierId[] =
28 "chrome://settings/display/notification/id-notifier";
29 const char kDownloadNotificationIdBase[] =
30 "chrome://settings/display/notification/id-";
31
32 } // anonymous namespace
33
34 DownloadNotificationItem::DownloadNotificationItem(
35 content::DownloadItem* item,
36 Delegate* delegate) :
37 openable_(false),
38 downloading_(false),
39 image_resource_id_(0),
40 item_(item),
41 delegate_(delegate) {
42 item->AddObserver(this);
43
44 message_center_ = message_center::MessageCenter::Get();
45
46 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
47
48 const base::string16 timeout_message =
49 l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING);
50 const base::string16 message =
51 l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
52
53 std::string id(kDownloadNotificationIdBase);
54 id += base::UintToString(item->GetId());
asanka 2015/02/10 02:25:30 Is the generated ID only expected to be valid for
yoshiki 2015/02/10 17:49:17 Download IDs are unique among profiles and notific
55
56 message_center::RichNotificationData data;
57 notification_.reset(new Notification(
58 message_center::NOTIFICATION_TYPE_PROGRESS,
59 id,
60 message,
61 timeout_message,
62 bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING),
63 base::string16() /* display_source */,
64 message_center::NotifierId(
65 message_center::NotifierId::SYSTEM_COMPONENT,
66 kDownloadNotificationNotifierId),
67 data,
68 this));
69
70 notification_->set_progress(0);
71 notification_->set_never_timeout(false);
72
73 SetNotificationData();
74
75 scoped_ptr<Notification> notification(new Notification(*notification_));
76 message_center_->AddNotification(notification.Pass());
77 }
78
79 DownloadNotificationItem::~DownloadNotificationItem() {
80 }
81
82 void DownloadNotificationItem::Close(bool by_user) {
83 bool is_popup = false;
84
85 const std::string id = notification_->id();
86 message_center::NotificationList::PopupNotifications popups =
87 message_center_->GetPopupNotifications();
88 for (auto it = popups.begin(); it != popups.end(); it++) {
89 if ((*it)->id() == id) {
90 is_popup = true;
91 }
92 }
93 LOG(ERROR) << "CLOSE: " << is_popup;
94
95 if (is_popup) {
96 notification_->set_is_read(true);
97 ShowNotificationAgainSoon();
98 } else {
99 item_->RemoveObserver(this);
100 item_->Cancel(by_user);
101 delegate_->OnDownloadNotificationItemDestroying(this);
102 }
103 }
104
105 void DownloadNotificationItem::ShowNotificationAgainSoon() {
106 content::BrowserThread::PostTask(
107 content::BrowserThread::UI,
108 FROM_HERE,
109 base::Bind(&DownloadNotificationItem::ShowNotificationAgain, this));
110 }
111
112 void DownloadNotificationItem::ShowNotificationAgain() {
113 scoped_ptr<Notification> notification(new Notification(*notification_));
114 message_center_->AddNotification(notification.Pass());
115 message_center_->MarkSinglePopupAsShown(
116 notification_->id(), notification_->IsRead());
117 }
118
119 void DownloadNotificationItem::Click() {
120 if (openable_)
121 item_->OpenDownload();
122 if (item_->IsDone()) {
123 message_center_->RemoveNotification(notification_->id(), true);
124 }
125 }
126
127 bool DownloadNotificationItem::HasClickedListener() {
128 return true;
129 }
130
131 void DownloadNotificationItem::ButtonClick(int button_index) {
132 if (button_index < 0 ||
133 static_cast<size_t>(button_index) >= button_actions_->size()) {
134 // Out of boundary. Do nothing.
135 return;
136 }
137
138 DownloadCommand::Commands command = button_actions_->at(button_index);
139 DownloadCommand(item_).ExecuteCommand(command, item_->GetWebContents());
140 }
141
142 // DownloadItem::Observer methods
143 void DownloadNotificationItem::OnDownloadUpdated(content::DownloadItem* item) {
144 DCHECK_EQ(item, item_);
145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
146
147 SetNotificationData();
148
149 // Updates notification.
150 scoped_ptr<Notification> notification(new Notification(*notification_));
151 message_center_->UpdateNotification(
152 notification->id(),
153 notification.Pass());
154 }
155
156 void DownloadNotificationItem::SetNotificationData() {
157 DownloadItemModel* model = new DownloadItemModel(item_);
158 DownloadCommand command(item_);
159
160 if (!downloading_) {
161 if (item_->GetState() == content::DownloadItem::IN_PROGRESS)
162 delegate_->OnDownloadStarted(this);
163 } else {
164 if (item_->GetState() != content::DownloadItem::IN_PROGRESS)
165 delegate_->OnDownloadStopped(this);
166 }
167
168 if (item_->IsDangerous()) {
169 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
170 notification_->set_title(GetTitle());
171 notification_->set_message(GetWarningTextLong());
172
173 // Show icon.
174
175 switch (item_->GetDangerType()) {
176 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
177 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
178 break;
179 default:
180 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS);
181 break;
182 }
183 } else {
184 notification_->set_title(GetTitle());
185 notification_->set_message(model->GetStatusText());
186
187 bool is_off_the_record = item_->GetBrowserContext()->IsOffTheRecord();
188
189 switch (item_->GetState()) {
190 case content::DownloadItem::IN_PROGRESS:
191 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
192 notification_->set_progress(item_->PercentComplete());
193 if (is_off_the_record) {
194 // TODO(yoshiki): Replace the tentative image.
195 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO);
196 } else {
197 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING);
198 }
199 break;
200 case content::DownloadItem::COMPLETE:
201 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
202 if (is_off_the_record) {
203 // TODO(yoshiki): Replace the tentative image.
204 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO);
205 } else {
206 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING);
207 }
208
209 // TODO(yoshiki): Popup a notification again.
210 break;
211 case content::DownloadItem::CANCELLED:
212 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
213 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_WARNING);
214 break;
215 case content::DownloadItem::INTERRUPTED:
216 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
217 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_WARNING);
218
219 // TODO(yoshiki): Popup a notification again.
220 break;
221 case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel
222 NOTREACHED();
223 }
224 }
225
226 std::vector<message_center::ButtonInfo> notification_actions;
227 scoped_ptr<std::vector<DownloadCommand::Commands> >
228 actions(GetPossibleActions().Pass());
229
230 openable_ = false;
231 button_actions_.reset(new std::vector<DownloadCommand::Commands>);
232 ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
233 for (auto it = actions->begin(); it != actions->end(); it++) {
234 if (*it == DownloadCommand::OPEN_WHEN_COMPLETE) {
235 openable_ = true;
236 } else {
237 button_actions_->push_back(*it);
238 message_center::ButtonInfo button_info = message_center::ButtonInfo(
239 l10n_util::GetStringUTF16(command.GetCommandStringId(*it)));
240 button_info.icon = bundle.GetImageNamed(command.GetCommandIconId(*it));
241 notification_actions.push_back(button_info);
242 }
243 }
244 notification_->set_buttons(notification_actions);
245
246 if (item_->IsDone()) {
247 // TODO(yoshiki): If the downloaded file is an image, show the thumbnail.
248 }
249 }
250
251 void DownloadNotificationItem::OnDownloadOpened(content::DownloadItem* item) {
252 DCHECK_EQ(item, item_);
253 // Do nothing.
254 }
255
256 void DownloadNotificationItem::OnDownloadDestroyed(
257 content::DownloadItem* item) {
258 DCHECK_EQ(item, item_);
259
260 // TODO(yoshiki): close the notification if necessary.
261
262 delegate_->OnDownloadNotificationItemDestroying(this);
263 }
264
265 void DownloadNotificationItem::SetImageToNotification(int resource_id) {
266 if (image_resource_id_ == resource_id)
267 return;
268 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
269 image_resource_id_ = resource_id;
270 notification_->set_icon(bundle.GetImageNamed(image_resource_id_));
271 }
272
273 scoped_ptr<std::vector<DownloadCommand::Commands> >
274 DownloadNotificationItem::GetPossibleActions() const {
275 scoped_ptr<std::vector<DownloadCommand::Commands> >
276 actions(new std::vector<DownloadCommand::Commands>());
277
278 if (item_->IsDangerous()) {
279 actions->push_back(DownloadCommand::DISCARD);
280 actions->push_back(DownloadCommand::SHOW_IN_FOLDER);
281 return actions.Pass();
282 }
283
284 switch (item_->GetState()) {
285 case content::DownloadItem::IN_PROGRESS:
286 actions->push_back(DownloadCommand::OPEN_WHEN_COMPLETE);
287 if (!item_->IsPaused())
288 actions->push_back(DownloadCommand::PAUSE);
289 else
290 actions->push_back(DownloadCommand::RESUME);
291 break;
292 case content::DownloadItem::CANCELLED:
293 case content::DownloadItem::INTERRUPTED:
294 actions->push_back(DownloadCommand::RETRY);
295 break;
296 case content::DownloadItem::COMPLETE:
297 actions->push_back(DownloadCommand::OPEN_WHEN_COMPLETE);
298 actions->push_back(DownloadCommand::SHOW_IN_FOLDER);
299 break;
300 case content::DownloadItem::MAX_DOWNLOAD_STATE:
301 NOTREACHED();
302 }
303 return actions.Pass();
304 }
305
306 base::string16 DownloadNotificationItem::GetTitle() const {
307 base::string16 title_text;
308 base::string16 file_name =
309 item_->GetFileNameToReportUser().LossyDisplayName();
310 switch (item_->GetState()) {
311 case content::DownloadItem::IN_PROGRESS:
312 title_text = l10n_util::GetStringFUTF16(
313 IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE,
314 file_name);
315 break;
316 case content::DownloadItem::COMPLETE:
317 title_text = l10n_util::GetStringFUTF16(
318 IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE,
319 file_name);
320 case content::DownloadItem::INTERRUPTED:
321 title_text = l10n_util::GetStringFUTF16(
322 IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE,
323 file_name);
324 break;
325 case content::DownloadItem::CANCELLED:
326 title_text = l10n_util::GetStringFUTF16(
327 IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE,
328 file_name);
329 break;
330 case content::DownloadItem::MAX_DOWNLOAD_STATE:
331 NOTREACHED();
332 }
333 return title_text;
334 }
335
336 base::string16 DownloadNotificationItem::GetWarningTextLong() const {
337 // Should only be called if IsDangerous().
338 DCHECK(item_->IsDangerous());
339 base::string16 elided_filename =
340 item_->GetFileNameToReportUser().LossyDisplayName();
341 switch (item_->GetDangerType()) {
342 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
343 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
344 }
345 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
346 if (download_crx_util::IsExtensionDownload(*item_)) {
347 return l10n_util::GetStringUTF16(
348 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
349 } else {
350 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
351 elided_filename);
352 }
353 }
354 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
355 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
356 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
357 elided_filename);
358 }
359 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
360 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
361 elided_filename);
362 }
363 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
364 return l10n_util::GetStringFUTF16(
365 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename);
366 }
367 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
368 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
369 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
370 case content::DOWNLOAD_DANGER_TYPE_MAX: {
371 break;
372 }
373 }
374 NOTREACHED();
375 return base::string16();
376 }
377
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698