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

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: Addressed comments 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());
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
94 if (is_popup) {
95 notification_->set_is_read(true);
96 ShowNotificationAgainSoon();
97 } else {
98 item_->RemoveObserver(this);
99 item_->Cancel(by_user);
100 delegate_->OnDownloadNotificationItemDestroying(this);
101 }
102 }
103
104 void DownloadNotificationItem::ShowNotificationAgainSoon() {
105 content::BrowserThread::PostTask(
106 content::BrowserThread::UI,
107 FROM_HERE,
108 base::Bind(&DownloadNotificationItem::ShowNotificationAgain, this));
109 }
110
111 void DownloadNotificationItem::ShowNotificationAgain() {
112 scoped_ptr<Notification> notification(new Notification(*notification_));
113 message_center_->AddNotification(notification.Pass());
114 message_center_->MarkSinglePopupAsShown(
115 notification_->id(), notification_->IsRead());
116 }
117
118 void DownloadNotificationItem::Click() {
119 if (openable_)
120 item_->OpenDownload();
121 if (item_->IsDone()) {
122 message_center_->RemoveNotification(notification_->id(), true);
123 }
124 }
125
126 bool DownloadNotificationItem::HasClickedListener() {
127 return true;
128 }
129
130 void DownloadNotificationItem::ButtonClick(int button_index) {
131 if (button_index < 0 ||
132 static_cast<size_t>(button_index) >= button_actions_->size()) {
133 // Out of boundary. Do nothing.
134 return;
135 }
136
137 DownloadCommands::Command command = button_actions_->at(button_index);
138 DownloadCommands(item_).ExecuteCommand(command, item_->GetWebContents());
139 }
140
141 // DownloadItem::Observer methods
142 void DownloadNotificationItem::OnDownloadUpdated(content::DownloadItem* item) {
143 DCHECK_EQ(item, item_);
144 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
145
146 SetNotificationData();
147
148 // Updates notification.
149 scoped_ptr<Notification> notification(new Notification(*notification_));
150 message_center_->UpdateNotification(
151 notification->id(),
152 notification.Pass());
153 }
154
155 void DownloadNotificationItem::SetNotificationData() {
156 DownloadItemModel* model = new DownloadItemModel(item_);
157 DownloadCommands command(item_);
158
159 if (!downloading_) {
160 if (item_->GetState() == content::DownloadItem::IN_PROGRESS)
161 delegate_->OnDownloadStarted(this);
162 } else {
163 if (item_->GetState() != content::DownloadItem::IN_PROGRESS)
164 delegate_->OnDownloadStopped(this);
165 }
166
167 if (item_->IsDangerous()) {
168 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
169 notification_->set_title(GetTitle());
170 notification_->set_message(GetWarningTextLong());
171
172 // Show icon.
173
174 switch (item_->GetDangerType()) {
175 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
176 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
177 break;
178 default:
179 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS);
180 break;
181 }
182 } else {
183 notification_->set_title(GetTitle());
184 notification_->set_message(model->GetStatusText());
185
186 bool is_off_the_record = item_->GetBrowserContext()->IsOffTheRecord();
187
188 switch (item_->GetState()) {
189 case content::DownloadItem::IN_PROGRESS:
190 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
191 notification_->set_progress(item_->PercentComplete());
192 if (is_off_the_record) {
193 // TODO(yoshiki): Replace the tentative image.
194 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO);
195 } else {
196 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING);
197 }
198 break;
199 case content::DownloadItem::COMPLETE:
200 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
201 if (is_off_the_record) {
202 // TODO(yoshiki): Replace the tentative image.
203 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO);
204 } else {
205 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING);
206 }
207
208 // TODO(yoshiki): Popup a notification again.
209 break;
210 case content::DownloadItem::CANCELLED:
211 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
212 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_WARNING);
213 break;
214 case content::DownloadItem::INTERRUPTED:
215 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
216 SetImageToNotification(IDR_DOWNLOAD_NOTIFICATION_WARNING);
217
218 // TODO(yoshiki): Popup a notification again.
219 break;
220 case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel
221 NOTREACHED();
222 }
223 }
224
225 std::vector<message_center::ButtonInfo> notification_actions;
226 scoped_ptr<std::vector<DownloadCommands::Command> >
227 actions(GetPossibleActions().Pass());
228
229 openable_ = false;
230 button_actions_.reset(new std::vector<DownloadCommands::Command>);
231 for (auto it = actions->begin(); it != actions->end(); it++) {
232 if (*it == DownloadCommands::OPEN_WHEN_COMPLETE) {
233 openable_ = true;
234 } else {
235 button_actions_->push_back(*it);
236 message_center::ButtonInfo button_info =
237 message_center::ButtonInfo(command.GetCommandString(*it));
238 button_info.icon = command.GetCommandIcon(*it);
239 notification_actions.push_back(button_info);
240 }
241 }
242 notification_->set_buttons(notification_actions);
243
244 if (item_->IsDone()) {
245 // TODO(yoshiki): If the downloaded file is an image, show the thumbnail.
246 }
247 }
248
249 void DownloadNotificationItem::OnDownloadOpened(content::DownloadItem* item) {
250 DCHECK_EQ(item, item_);
251 // Do nothing.
252 }
253
254 void DownloadNotificationItem::OnDownloadDestroyed(
255 content::DownloadItem* item) {
256 DCHECK_EQ(item, item_);
257
258 // TODO(yoshiki): close the notification if necessary.
259
260 delegate_->OnDownloadNotificationItemDestroying(this);
261 }
262
263 void DownloadNotificationItem::SetImageToNotification(int resource_id) {
264 if (image_resource_id_ == resource_id)
265 return;
266 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
267 image_resource_id_ = resource_id;
268 notification_->set_icon(bundle.GetImageNamed(image_resource_id_));
269 }
270
271 scoped_ptr<std::vector<DownloadCommands::Command> >
272 DownloadNotificationItem::GetPossibleActions() const {
273 scoped_ptr<std::vector<DownloadCommands::Command> >
274 actions(new std::vector<DownloadCommands::Command>());
275
276 if (item_->IsDangerous()) {
277 actions->push_back(DownloadCommands::DISCARD);
278 actions->push_back(DownloadCommands::SHOW_IN_FOLDER);
279 return actions.Pass();
280 }
281
282 switch (item_->GetState()) {
283 case content::DownloadItem::IN_PROGRESS:
284 actions->push_back(DownloadCommands::OPEN_WHEN_COMPLETE);
285 if (!item_->IsPaused())
286 actions->push_back(DownloadCommands::PAUSE);
287 else
288 actions->push_back(DownloadCommands::RESUME);
289 break;
290 case content::DownloadItem::CANCELLED:
291 case content::DownloadItem::INTERRUPTED:
292 actions->push_back(DownloadCommands::RETRY);
293 break;
294 case content::DownloadItem::COMPLETE:
295 actions->push_back(DownloadCommands::OPEN_WHEN_COMPLETE);
296 actions->push_back(DownloadCommands::SHOW_IN_FOLDER);
297 break;
298 case content::DownloadItem::MAX_DOWNLOAD_STATE:
299 NOTREACHED();
300 }
301 return actions.Pass();
302 }
303
304 base::string16 DownloadNotificationItem::GetTitle() const {
305 base::string16 title_text;
306 base::string16 file_name =
307 item_->GetFileNameToReportUser().LossyDisplayName();
308 switch (item_->GetState()) {
309 case content::DownloadItem::IN_PROGRESS:
310 title_text = l10n_util::GetStringFUTF16(
311 IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE,
312 file_name);
313 break;
314 case content::DownloadItem::COMPLETE:
315 title_text = l10n_util::GetStringFUTF16(
316 IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE,
317 file_name);
318 case content::DownloadItem::INTERRUPTED:
319 title_text = l10n_util::GetStringFUTF16(
320 IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE,
321 file_name);
322 break;
323 case content::DownloadItem::CANCELLED:
324 title_text = l10n_util::GetStringFUTF16(
325 IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE,
326 file_name);
327 break;
328 case content::DownloadItem::MAX_DOWNLOAD_STATE:
329 NOTREACHED();
330 }
331 return title_text;
332 }
333
334 base::string16 DownloadNotificationItem::GetWarningTextLong() const {
335 // Should only be called if IsDangerous().
336 DCHECK(item_->IsDangerous());
337 base::string16 elided_filename =
338 item_->GetFileNameToReportUser().LossyDisplayName();
339 switch (item_->GetDangerType()) {
340 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
341 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
342 }
343 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
344 if (download_crx_util::IsExtensionDownload(*item_)) {
345 return l10n_util::GetStringUTF16(
346 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
347 } else {
348 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
349 elided_filename);
350 }
351 }
352 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
353 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
354 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
355 elided_filename);
356 }
357 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
358 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
359 elided_filename);
360 }
361 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
362 return l10n_util::GetStringFUTF16(
363 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, elided_filename);
364 }
365 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
366 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
367 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
368 case content::DOWNLOAD_DANGER_TYPE_MAX: {
369 break;
370 }
371 }
372 NOTREACHED();
373 return base::string16();
374 }
375
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698