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

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

Powered by Google App Engine
This is Rietveld 408576698