OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/download/notification/download_notification_item.h" | 5 #include "chrome/browser/download/notification/download_notification_item.h" |
6 | 6 |
| 7 #include "base/files/file_util.h" |
7 #include "chrome/browser/browser_process.h" | 8 #include "chrome/browser/browser_process.h" |
8 #include "chrome/browser/download/download_crx_util.h" | 9 #include "chrome/browser/download/download_crx_util.h" |
9 #include "chrome/browser/download/download_item_model.h" | 10 #include "chrome/browser/download/download_item_model.h" |
10 #include "chrome/browser/download/notification/download_notification_manager.h" | 11 #include "chrome/browser/download/notification/download_notification_manager.h" |
11 #include "chrome/browser/notifications/notification.h" | 12 #include "chrome/browser/notifications/notification.h" |
12 #include "chrome/browser/notifications/notification_ui_manager.h" | 13 #include "chrome/browser/notifications/notification_ui_manager.h" |
13 #include "chrome/browser/notifications/profile_notification.h" | 14 #include "chrome/browser/notifications/profile_notification.h" |
14 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" | 15 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" |
15 #include "chrome/common/url_constants.h" | 16 #include "chrome/common/url_constants.h" |
16 #include "chrome/grit/chromium_strings.h" | 17 #include "chrome/grit/chromium_strings.h" |
17 #include "chrome/grit/generated_resources.h" | 18 #include "chrome/grit/generated_resources.h" |
| 19 #include "components/mime_util/mime_util.h" |
18 #include "content/public/browser/browser_context.h" | 20 #include "content/public/browser/browser_context.h" |
19 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
20 #include "content/public/browser/download_interrupt_reasons.h" | 22 #include "content/public/browser/download_interrupt_reasons.h" |
21 #include "content/public/browser/download_item.h" | 23 #include "content/public/browser/download_item.h" |
22 #include "content/public/browser/page_navigator.h" | 24 #include "content/public/browser/page_navigator.h" |
23 #include "content/public/browser/web_contents.h" | 25 #include "content/public/browser/web_contents.h" |
24 #include "grit/theme_resources.h" | 26 #include "grit/theme_resources.h" |
| 27 #include "net/base/mime_util.h" |
25 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
26 #include "ui/base/resource/resource_bundle.h" | 29 #include "ui/base/resource/resource_bundle.h" |
| 30 #include "ui/gfx/codec/jpeg_codec.h" |
| 31 #include "ui/gfx/image/image.h" |
27 #include "ui/message_center/message_center.h" | 32 #include "ui/message_center/message_center.h" |
28 | 33 |
29 namespace { | 34 namespace { |
30 | 35 |
31 const char kDownloadNotificationNotifierId[] = | 36 const char kDownloadNotificationNotifierId[] = |
32 "chrome://downloads/notification/id-notifier"; | 37 "chrome://downloads/notification/id-notifier"; |
33 | 38 |
| 39 // Maximum size of preview image. If the image exceeds this size, don't show the |
| 40 // preview image. |
| 41 const int64 kMaxImagePreviewSize = 10 * 1024 * 1024; // 10 MB |
| 42 |
| 43 std::string ReadNotificationImage(const base::FilePath& file_path) { |
| 44 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
| 45 |
| 46 std::string data; |
| 47 bool ret = base::ReadFileToString(file_path, &data); |
| 48 if (!ret) |
| 49 return std::string(); |
| 50 |
| 51 DCHECK_LE(data.size(), static_cast<size_t>(kMaxImagePreviewSize)); |
| 52 |
| 53 return data; |
| 54 } |
| 55 |
34 } // anonymous namespace | 56 } // anonymous namespace |
35 | 57 |
36 DownloadNotificationItem::DownloadNotificationItem( | 58 DownloadNotificationItem::DownloadNotificationItem( |
37 content::DownloadItem* item, | 59 content::DownloadItem* item, |
38 DownloadNotificationManagerForProfile* manager) | 60 DownloadNotificationManagerForProfile* manager) |
39 : item_(item) { | 61 : item_(item), |
| 62 weak_factory_(this) { |
40 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | 63 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
41 | 64 |
42 message_center::RichNotificationData data; | 65 message_center::RichNotificationData data; |
43 // Creates the notification instance. |title| and |body| will be overridden | 66 // Creates the notification instance. |title| and |body| will be overridden |
44 // by UpdateNotificationData() below. | 67 // by UpdateNotificationData() below. |
45 notification_.reset(new Notification( | 68 notification_.reset(new Notification( |
46 message_center::NOTIFICATION_TYPE_PROGRESS, | 69 message_center::NOTIFICATION_TYPE_PROGRESS, |
47 GURL(kDownloadNotificationOrigin), // origin_url | 70 GURL(kDownloadNotificationOrigin), // origin_url |
48 base::string16(), // title | 71 base::string16(), // title |
49 base::string16(), // body | 72 base::string16(), // body |
50 bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING), | 73 bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING), |
51 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, | 74 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, |
52 kDownloadNotificationNotifierId), | 75 kDownloadNotificationNotifierId), |
53 base::string16(), // display_source | 76 base::string16(), // display_source |
54 base::UintToString(item_->GetId()), // tag | 77 base::UintToString(item_->GetId()), // tag |
55 data, watcher())); | 78 data, watcher())); |
56 | 79 |
57 notification_->set_progress(0); | 80 notification_->set_progress(0); |
58 notification_->set_never_timeout(false); | 81 notification_->set_never_timeout(false); |
59 } | 82 } |
60 | 83 |
61 DownloadNotificationItem::~DownloadNotificationItem() { | 84 DownloadNotificationItem::~DownloadNotificationItem() { |
| 85 if (image_decode_status_ == IN_PROGRESS) |
| 86 ImageDecoder::Cancel(this); |
62 } | 87 } |
63 | 88 |
64 void DownloadNotificationItem::OnNotificationClose() { | 89 void DownloadNotificationItem::OnNotificationClose() { |
65 visible_ = false; | 90 visible_ = false; |
| 91 |
| 92 if (image_decode_status_ == IN_PROGRESS) { |
| 93 image_decode_status_ = NOT_STARTED; |
| 94 ImageDecoder::Cancel(this); |
| 95 } |
66 } | 96 } |
67 | 97 |
68 void DownloadNotificationItem::OnNotificationClick() { | 98 void DownloadNotificationItem::OnNotificationClick() { |
69 if (item_->IsDangerous()) { | 99 if (item_->IsDangerous()) { |
70 #if defined(FULL_SAFE_BROWSING) | 100 #if defined(FULL_SAFE_BROWSING) |
71 DownloadCommands(item_).ExecuteCommand( | 101 DownloadCommands(item_).ExecuteCommand( |
72 DownloadCommands::LEARN_MORE_SCANNING); | 102 DownloadCommands::LEARN_MORE_SCANNING); |
73 #else | 103 #else |
74 CloseNotificationByUser(); | 104 CloseNotificationByUser(); |
75 #endif | 105 #endif |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 visible_ = true; | 209 visible_ = true; |
180 } | 210 } |
181 } | 211 } |
182 | 212 |
183 show_next_ = false; | 213 show_next_ = false; |
184 previous_download_state_ = item_->GetState(); | 214 previous_download_state_ = item_->GetState(); |
185 } | 215 } |
186 | 216 |
187 void DownloadNotificationItem::UpdateNotificationData( | 217 void DownloadNotificationItem::UpdateNotificationData( |
188 NotificationUpdateType type) { | 218 NotificationUpdateType type) { |
| 219 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 220 |
189 DownloadItemModel model(item_); | 221 DownloadItemModel model(item_); |
190 DownloadCommands command(item_); | 222 DownloadCommands command(item_); |
191 | 223 |
192 if (item_->IsDangerous()) { | 224 if (item_->IsDangerous()) { |
193 notification_->set_type(message_center::NOTIFICATION_TYPE_BASE_FORMAT); | 225 notification_->set_type(message_center::NOTIFICATION_TYPE_BASE_FORMAT); |
194 notification_->set_title(GetTitle()); | 226 notification_->set_title(GetTitle()); |
195 notification_->set_message(GetWarningText()); | 227 notification_->set_message(GetWarningText()); |
196 | 228 |
197 // Show icon. | 229 // Show icon. |
198 SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS); | 230 SetNotificationIcon(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS); |
199 } else { | 231 } else { |
200 notification_->set_title(GetTitle()); | 232 notification_->set_title(GetTitle()); |
201 notification_->set_message(model.GetStatusText()); | 233 notification_->set_message(model.GetStatusText()); |
202 | 234 |
203 bool is_off_the_record = item_->GetBrowserContext() && | 235 bool is_off_the_record = item_->GetBrowserContext() && |
204 item_->GetBrowserContext()->IsOffTheRecord(); | 236 item_->GetBrowserContext()->IsOffTheRecord(); |
205 | 237 |
206 switch (item_->GetState()) { | 238 switch (item_->GetState()) { |
207 case content::DownloadItem::IN_PROGRESS: | 239 case content::DownloadItem::IN_PROGRESS: |
208 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); | 240 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); |
209 notification_->set_progress(item_->PercentComplete()); | 241 notification_->set_progress(item_->PercentComplete()); |
210 if (is_off_the_record) { | 242 if (is_off_the_record) { |
211 // TODO(yoshiki): Replace the tentative image. | 243 // TODO(yoshiki): Replace the tentative image. |
212 SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO); | 244 SetNotificationIcon(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO); |
213 } else { | 245 } else { |
214 SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); | 246 SetNotificationIcon(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); |
215 } | 247 } |
216 break; | 248 break; |
217 case content::DownloadItem::COMPLETE: | 249 case content::DownloadItem::COMPLETE: |
218 DCHECK(item_->IsDone()); | 250 DCHECK(item_->IsDone()); |
219 | 251 |
220 // Shows a notifiation as progress type once so the visible content will | 252 // Shows a notifiation as progress type once so the visible content will |
221 // be updated. | 253 // be updated. |
222 // Note: only progress-type notification's content will be updated | 254 // Note: only progress-type notification's content will be updated |
223 // immediately when the message center is visible. | 255 // immediately when the message center is visible. |
224 if (type == UPDATE_AND_POPUP) { | 256 if (type == UPDATE_AND_POPUP) { |
225 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); | 257 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); |
226 } else { | 258 } else { |
227 notification_->set_type( | 259 notification_->set_type( |
228 message_center::NOTIFICATION_TYPE_BASE_FORMAT); | 260 message_center::NOTIFICATION_TYPE_BASE_FORMAT); |
229 } | 261 } |
230 | 262 |
231 notification_->set_progress(100); | 263 notification_->set_progress(100); |
232 | 264 |
233 if (is_off_the_record) { | 265 if (is_off_the_record) { |
234 // TODO(yoshiki): Replace the tentative image. | 266 // TODO(yoshiki): Replace the tentative image. |
235 SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO); | 267 SetNotificationIcon(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO); |
236 } else { | 268 } else { |
237 SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); | 269 SetNotificationIcon(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING); |
238 } | 270 } |
239 break; | 271 break; |
240 case content::DownloadItem::CANCELLED: | 272 case content::DownloadItem::CANCELLED: |
241 // Confgirms that a download is cancelled by user action. | 273 // Confgirms that a download is cancelled by user action. |
242 DCHECK(item_->GetLastReason() == | 274 DCHECK(item_->GetLastReason() == |
243 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED || | 275 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED || |
244 item_->GetLastReason() == | 276 item_->GetLastReason() == |
245 content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN); | 277 content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN); |
246 | 278 |
247 CloseNotificationByUser(); | 279 CloseNotificationByUser(); |
248 return; // Skips the remaining since the notification has closed. | 280 return; // Skips the remaining since the notification has closed. |
249 case content::DownloadItem::INTERRUPTED: | 281 case content::DownloadItem::INTERRUPTED: |
250 // Shows a notifiation as progress type once so the visible content will | 282 // Shows a notifiation as progress type once so the visible content will |
251 // be updated. (same as the case of type = COMPLETE) | 283 // be updated. (same as the case of type = COMPLETE) |
252 if (type == UPDATE_AND_POPUP) { | 284 if (type == UPDATE_AND_POPUP) { |
253 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); | 285 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); |
254 } else { | 286 } else { |
255 notification_->set_type( | 287 notification_->set_type( |
256 message_center::NOTIFICATION_TYPE_BASE_FORMAT); | 288 message_center::NOTIFICATION_TYPE_BASE_FORMAT); |
257 } | 289 } |
258 | 290 |
259 notification_->set_progress(0); | 291 notification_->set_progress(0); |
260 SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_WARNING); | 292 SetNotificationIcon(IDR_DOWNLOAD_NOTIFICATION_WARNING); |
261 break; | 293 break; |
262 case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel | 294 case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel |
263 NOTREACHED(); | 295 NOTREACHED(); |
264 } | 296 } |
265 } | 297 } |
266 | 298 |
267 std::vector<message_center::ButtonInfo> notification_actions; | 299 std::vector<message_center::ButtonInfo> notification_actions; |
268 scoped_ptr<std::vector<DownloadCommands::Command>> actions( | 300 scoped_ptr<std::vector<DownloadCommands::Command>> actions( |
269 GetExtraActions().Pass()); | 301 GetExtraActions().Pass()); |
270 | 302 |
271 button_actions_.reset(new std::vector<DownloadCommands::Command>); | 303 button_actions_.reset(new std::vector<DownloadCommands::Command>); |
272 for (auto it = actions->begin(); it != actions->end(); it++) { | 304 for (auto it = actions->begin(); it != actions->end(); it++) { |
273 button_actions_->push_back(*it); | 305 button_actions_->push_back(*it); |
274 message_center::ButtonInfo button_info = | 306 message_center::ButtonInfo button_info = |
275 message_center::ButtonInfo(GetCommandLabel(*it)); | 307 message_center::ButtonInfo(GetCommandLabel(*it)); |
276 button_info.icon = command.GetCommandIcon(*it); | 308 button_info.icon = command.GetCommandIcon(*it); |
277 notification_actions.push_back(button_info); | 309 notification_actions.push_back(button_info); |
278 } | 310 } |
279 notification_->set_buttons(notification_actions); | 311 notification_->set_buttons(notification_actions); |
280 | 312 |
281 if (item_->IsDone()) { | |
282 // TODO(yoshiki): If the downloaded file is an image, show the thumbnail. | |
283 } | |
284 | |
285 if (type == ADD) { | 313 if (type == ADD) { |
286 g_browser_process->notification_ui_manager()-> | 314 g_browser_process->notification_ui_manager()-> |
287 Add(*notification_, profile()); | 315 Add(*notification_, profile()); |
288 } else if (type == UPDATE || type == UPDATE_AND_POPUP) { | 316 } else if (type == UPDATE || type == UPDATE_AND_POPUP) { |
289 g_browser_process->notification_ui_manager()-> | 317 g_browser_process->notification_ui_manager()-> |
290 Update(*notification_, profile()); | 318 Update(*notification_, profile()); |
291 | 319 |
292 if (type == UPDATE_AND_POPUP) { | 320 if (type == UPDATE_AND_POPUP) { |
293 CloseNotificationByNonUser(); | 321 CloseNotificationByNonUser(); |
294 // Changes the type from PROGRESS to BASE_FORMAT. | 322 // Changes the type from PROGRESS to BASE_FORMAT. |
295 notification_->set_type(message_center::NOTIFICATION_TYPE_BASE_FORMAT); | 323 notification_->set_type(message_center::NOTIFICATION_TYPE_BASE_FORMAT); |
296 g_browser_process->notification_ui_manager()-> | 324 g_browser_process->notification_ui_manager()-> |
297 Add(*notification_, profile()); | 325 Add(*notification_, profile()); |
298 } | 326 } |
299 } else { | 327 } else { |
300 NOTREACHED(); | 328 NOTREACHED(); |
301 } | 329 } |
| 330 |
| 331 if (item_->IsDone() && image_decode_status_ == NOT_STARTED) { |
| 332 // TODO(yoshiki): Add an UMA to collect statistics of image file sizes. |
| 333 |
| 334 if (item_->GetReceivedBytes() > kMaxImagePreviewSize) |
| 335 return; |
| 336 |
| 337 DCHECK(notification_->image().IsEmpty()); |
| 338 |
| 339 image_decode_status_ = IN_PROGRESS; |
| 340 |
| 341 bool maybe_image = false; |
| 342 if (mime_util::IsSupportedImageMimeType(item_->GetMimeType())) { |
| 343 maybe_image = true; |
| 344 } else { |
| 345 std::string mime; |
| 346 base::FilePath::StringType extension_with_dot = |
| 347 item_->GetTargetFilePath().FinalExtension(); |
| 348 if (!extension_with_dot.empty() && |
| 349 net::GetWellKnownMimeTypeFromExtension(extension_with_dot.substr(1), |
| 350 &mime) && |
| 351 mime_util::IsSupportedImageMimeType(mime)) { |
| 352 maybe_image = true; |
| 353 } |
| 354 } |
| 355 |
| 356 if (maybe_image) { |
| 357 base::FilePath file_path = item_->GetFullPath(); |
| 358 base::PostTaskAndReplyWithResult( |
| 359 content::BrowserThread::GetBlockingPool(), FROM_HERE, |
| 360 base::Bind(&ReadNotificationImage, file_path), |
| 361 base::Bind(&DownloadNotificationItem::OnImageLoaded, |
| 362 weak_factory_.GetWeakPtr())); |
| 363 } |
| 364 } |
302 } | 365 } |
303 | 366 |
304 void DownloadNotificationItem::OnDownloadRemoved(content::DownloadItem* item) { | 367 void DownloadNotificationItem::OnDownloadRemoved(content::DownloadItem* item) { |
305 // The given |item| may be already free'd. | 368 // The given |item| may be already free'd. |
306 DCHECK_EQ(item, item_); | 369 DCHECK_EQ(item, item_); |
307 | 370 |
308 // Removing the notification causes calling |NotificationDelegate::Close()|. | 371 // Removing the notification causes calling |NotificationDelegate::Close()|. |
309 if (g_browser_process->notification_ui_manager()) { | 372 if (g_browser_process->notification_ui_manager()) { |
310 g_browser_process->notification_ui_manager()->CancelById( | 373 g_browser_process->notification_ui_manager()->CancelById( |
311 watcher()->id(), NotificationUIManager::GetProfileID(profile())); | 374 watcher()->id(), NotificationUIManager::GetProfileID(profile())); |
312 } | 375 } |
313 | 376 |
314 item_ = nullptr; | 377 item_ = nullptr; |
315 } | 378 } |
316 | 379 |
317 void DownloadNotificationItem::SetNotificationImage(int resource_id) { | 380 void DownloadNotificationItem::SetNotificationIcon(int resource_id) { |
318 if (image_resource_id_ == resource_id) | 381 if (image_resource_id_ == resource_id) |
319 return; | 382 return; |
320 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | 383 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
321 image_resource_id_ = resource_id; | 384 image_resource_id_ = resource_id; |
322 notification_->set_icon(bundle.GetImageNamed(image_resource_id_)); | 385 notification_->set_icon(bundle.GetImageNamed(image_resource_id_)); |
323 } | 386 } |
324 | 387 |
| 388 void DownloadNotificationItem::OnImageLoaded(const std::string& image_data) { |
| 389 if (image_data.empty()) |
| 390 return; |
| 391 |
| 392 // TODO(yoshiki): Set option to reduce the image size to supress memory usage. |
| 393 ImageDecoder::Start(this, image_data); |
| 394 } |
| 395 |
| 396 void DownloadNotificationItem::OnImageDecoded(const SkBitmap& decoded_image) { |
| 397 gfx::Image image = gfx::Image::CreateFrom1xBitmap(decoded_image); |
| 398 notification_->set_image(image); |
| 399 image_decode_status_ = DONE; |
| 400 UpdateNotificationData(UPDATE); |
| 401 } |
| 402 |
| 403 void DownloadNotificationItem::OnDecodeImageFailed() { |
| 404 DCHECK(notification_->image().IsEmpty()); |
| 405 |
| 406 image_decode_status_ = FAILED; |
| 407 UpdateNotificationData(UPDATE); |
| 408 } |
| 409 |
325 scoped_ptr<std::vector<DownloadCommands::Command>> | 410 scoped_ptr<std::vector<DownloadCommands::Command>> |
326 DownloadNotificationItem::GetExtraActions() const { | 411 DownloadNotificationItem::GetExtraActions() const { |
327 scoped_ptr<std::vector<DownloadCommands::Command>> actions( | 412 scoped_ptr<std::vector<DownloadCommands::Command>> actions( |
328 new std::vector<DownloadCommands::Command>()); | 413 new std::vector<DownloadCommands::Command>()); |
329 | 414 |
330 if (item_->IsDangerous()) { | 415 if (item_->IsDangerous()) { |
331 actions->push_back(DownloadCommands::DISCARD); | 416 actions->push_back(DownloadCommands::DISCARD); |
332 actions->push_back(DownloadCommands::KEEP); | 417 actions->push_back(DownloadCommands::KEEP); |
333 return actions.Pass(); | 418 return actions.Pass(); |
334 } | 419 } |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 Browser* DownloadNotificationItem::GetBrowser() const { | 554 Browser* DownloadNotificationItem::GetBrowser() const { |
470 chrome::ScopedTabbedBrowserDisplayer browser_displayer( | 555 chrome::ScopedTabbedBrowserDisplayer browser_displayer( |
471 profile(), chrome::GetActiveDesktop()); | 556 profile(), chrome::GetActiveDesktop()); |
472 DCHECK(browser_displayer.browser()); | 557 DCHECK(browser_displayer.browser()); |
473 return browser_displayer.browser(); | 558 return browser_displayer.browser(); |
474 } | 559 } |
475 | 560 |
476 Profile* DownloadNotificationItem::profile() const { | 561 Profile* DownloadNotificationItem::profile() const { |
477 return Profile::FromBrowserContext(item_->GetBrowserContext()); | 562 return Profile::FromBrowserContext(item_->GetBrowserContext()); |
478 } | 563 } |
OLD | NEW |