OLD | NEW |
---|---|
(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 | |
OLD | NEW |