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

Side by Side Diff: ash/system/web_notification/web_notification_tray.cc

Issue 10514008: Add WebNotificationTray (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "ash/system/web_notification/web_notification_tray.h"
6
7 #include "ash/shell.h"
8 #include "ash/system/status_area_widget.h"
9 #include "ash/system/status_area_widget.h"
10 #include "ash/system/tray/system_tray_bubble_view.h"
11 #include "ash/system/tray/tray_constants.h"
12 #include "ash/system/tray/tray_views.h"
13 #include "grit/ash_strings.h"
14 #include "grit/ui_resources.h"
15 #include "grit/ui_resources_standard.h"
16 #include "ui/aura/event.h"
17 #include "ui/aura/window.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/models/simple_menu_model.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/views/controls/button/button.h"
22 #include "ui/views/controls/button/menu_button.h"
23 #include "ui/views/controls/button/menu_button_listener.h"
24 #include "ui/views/controls/label.h"
25 #include "ui/views/controls/menu/menu_model_adapter.h"
26 #include "ui/views/controls/menu/menu_runner.h"
27 #include "ui/views/layout/box_layout.h"
28 #include "ui/views/layout/fill_layout.h"
29 #include "ui/views/layout/grid_layout.h"
30
31 namespace {
32
33 const int kIconBorder = 4;
34 const int kImageWidth = 40;
35 const int kImageHeight = 25;
36 const int kWebNotificationBubbleMinHeight = 50;
37 const int kWebNotificationBubbleMaxHeight = 400;
38 const int kWebNotificationWidth = 400;
39 const int kWebNotificationButtonWidth = 32;
40
41 const int kTogglePermissionCommand = 0;
42 const int kToggleExtensionCommand = 1;
43 const int kShowSettingsCommand = 2;
44
45 // The image has three icons: 1 notifiaction, 2 notifications, and 3+.
46 SkBitmap GetNotificationImage(int notification_count) {
47 SkBitmap image;
48 gfx::Image all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
49 IDR_AURA_UBER_TRAY_WEB_NOTIFICATON);
50
51 int image_index = notification_count - 1;
52 image_index = std::max(0, std::min(image_index, 2));
53
54 SkIRect region = SkIRect::MakeXYWH(
55 0, image_index * kImageHeight, kImageWidth, kImageHeight);
56 all.ToSkBitmap()->extractSubset(&image, region);
57 return image;
58 }
59
60 } // namespace
61
62 namespace ash {
63
64 namespace internal {
65
66 struct WebNotification {
67 WebNotification(const std::string& i,
68 const string16& t,
69 const string16& m,
70 const string16& s,
71 const std::string& e)
72 : id(i),
73 title(t),
74 message(m),
75 display_source(s),
76 extension_id(e) {
77 }
78
79 std::string id;
80 string16 title;
81 string16 message;
82 string16 display_source;
83 std::string extension_id;
84 SkBitmap image;
85 };
86
87 // A helper class to manage the list of notifications.
88 class WebNotificationList {
89 public:
90 typedef std::list<WebNotification> Notifications;
91
92 WebNotificationList() {
93 }
94
95 void AddNotification(const std::string& id,
96 const string16& title,
97 const string16& message,
98 const string16& source,
99 const std::string& extension) {
100 Notifications::iterator iter = GetNotification(id);
101 if (iter != notifications_.end()) {
102 iter->title = title;
103 iter->message = message;
104 iter->display_source = source;
105 iter->extension_id = extension;
106 } else {
107 notifications_.push_back(
108 WebNotification(id, title, message, source, extension));
109 }
110 }
111
112 bool RemoveNotification(const std::string& id) {
113 Notifications::iterator iter = GetNotification(id);
114 if (iter == notifications_.end())
115 return false;
116 notifications_.erase(iter);
117 return true;
118 }
119
120 void RemoveNotificationsBySource(const std::string& id) {
121 Notifications::iterator source_iter = GetNotification(id);
122 if (source_iter == notifications_.end())
123 return;
124 string16 display_source = source_iter->display_source;
125 for (Notifications::iterator loopiter = notifications_.begin();
126 loopiter != notifications_.end(); ) {
127 Notifications::iterator curiter = loopiter++;
128 if (curiter->display_source == display_source)
129 notifications_.erase(curiter);
130 }
131 }
132
133 void RemoveNotificationsByExtension(const std::string& id) {
134 Notifications::iterator source_iter = GetNotification(id);
135 if (source_iter == notifications_.end())
136 return;
137 std::string extension_id = source_iter->extension_id;
138 for (Notifications::iterator loopiter = notifications_.begin();
139 loopiter != notifications_.end(); ) {
140 Notifications::iterator curiter = loopiter++;
141 if (curiter->extension_id == extension_id)
142 notifications_.erase(curiter);
143 }
144 }
145
146 bool SetNotificationImage(const std::string& id,
147 const SkBitmap& image) {
148 Notifications::iterator iter = GetNotification(id);
149 if (iter == notifications_.end())
150 return false;
151 iter->image = image;
152 return true;
153 }
154
155 const Notifications& notifications() const { return notifications_; }
156
157 private:
158 Notifications::iterator GetNotification(const std::string& id) {
159 for (Notifications::iterator iter = notifications_.begin();
160 iter != notifications_.end(); ++iter) {
161 if (iter->id == id)
162 return iter;
163 }
164 return notifications_.end();
165 }
166
167 Notifications notifications_;
168
169 DISALLOW_COPY_AND_ASSIGN(WebNotificationList);
170 };
171
172 // A simple view for the text (title and message) of a notification.
173 class WebNotificationMessageView : public views::View {
174 public:
175 explicit WebNotificationMessageView(const WebNotification& notification) {
176 views::Label* title = new views::Label(notification.title);
177 title->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
178 title->SetFont(title->font().DeriveFont(0, gfx::Font::BOLD));
179 views::Label* message = new views::Label(notification.message);
180 message->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
181 message->SetMultiLine(true);
182
183 SetLayoutManager(
184 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
185 AddChildView(title);
186 AddChildView(message);
187 }
188
189 virtual ~WebNotificationMessageView() {
190 }
191
192 private:
193 DISALLOW_COPY_AND_ASSIGN(WebNotificationMessageView);
194 };
195
196 // A dropdown menu for notifications.
197 class WebNotificationMenuModel : public ui::SimpleMenuModel,
198 public ui::SimpleMenuModel::Delegate {
199 public:
200 explicit WebNotificationMenuModel(WebNotificationTray* tray,
201 const WebNotification& notification)
202 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)),
203 tray_(tray),
204 notification_(notification) {
205 // Add 'disable notifications' menu item.
206 if (!notification.extension_id.empty()) {
207 AddItem(kToggleExtensionCommand,
208 GetLabelForCommandId(kToggleExtensionCommand));
209 } else if (!notification.display_source.empty()) {
210 AddItem(kTogglePermissionCommand,
211 GetLabelForCommandId(kTogglePermissionCommand));
212 }
213 // Add settings menu item.
214 if (!notification.display_source.empty()) {
215 AddItem(kShowSettingsCommand,
216 GetLabelForCommandId(kShowSettingsCommand));
217 }
218 }
219
220 virtual ~WebNotificationMenuModel() {
221 }
222
223 // Overridden from ui::SimpleMenuModel:
224 virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE {
225 switch (command_id) {
226 case kToggleExtensionCommand:
227 return l10n_util::GetStringUTF16(
228 IDS_ASH_WEB_NOTFICATION_TRAY_EXTENSIONS_DISABLE);
229 case kTogglePermissionCommand:
230 return l10n_util::GetStringFUTF16(
231 IDS_ASH_WEB_NOTFICATION_TRAY_SITE_DISABLE,
232 notification_.display_source);
233 case kShowSettingsCommand:
234 return l10n_util::GetStringUTF16(
235 IDS_ASH_WEB_NOTFICATION_TRAY_SETTINGS);
236 default:
237 NOTREACHED();
238 }
239 return string16();
240 }
241
242 // Overridden from ui::SimpleMenuModel::Delegate:
243 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
244 return false;
245 }
246
247 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
248 return true;
249 }
250
251 virtual bool GetAcceleratorForCommandId(
252 int command_id,
253 ui::Accelerator* accelerator) OVERRIDE {
254 return false;
255 }
256
257 virtual void ExecuteCommand(int command_id) OVERRIDE {
258 switch (command_id) {
259 case kToggleExtensionCommand:
260 tray_->DisableByExtension(notification_.id);
261 break;
262 case kTogglePermissionCommand:
263 tray_->DisableByUrl(notification_.id);
264 break;
265 case kShowSettingsCommand:
266 tray_->ShowSettings(notification_.id);
267 break;
268 default:
269 NOTREACHED();
270 }
271 }
272
273 private:
274 WebNotificationTray* tray_;
275 WebNotification notification_;
276
277 DISALLOW_COPY_AND_ASSIGN(WebNotificationMenuModel);
278 };
279
280 // The view for a notification entry (icon + message + buttons).
281 class WebNotificationView : public views::View,
282 public views::ButtonListener,
283 public views::MenuButtonListener {
284 public:
285 WebNotificationView(WebNotificationTray* tray,
286 const WebNotification& notification)
287 : tray_(tray),
288 notification_(notification),
289 icon_(NULL),
290 menu_button_(NULL),
291 close_button_(NULL) {
292 InitView(tray, notification);
293 }
294
295 virtual ~WebNotificationView() {
296 }
297
298 void InitView(WebNotificationTray* tray,
299 const WebNotification& notification) {
300 set_border(views::Border::CreateSolidSidedBorder(
301 1, 0, 0, 0, kBorderLightColor));
302 set_background(views::Background::CreateSolidBackground(kBackgroundColor));
303
304 icon_ = new views::ImageView;
305 icon_->SetImage(notification.image);
306
307 WebNotificationMessageView* message_view
308 = new WebNotificationMessageView(notification);
309
310 close_button_ = new views::ImageButton(this);
311 close_button_->SetImage(
312 views::CustomButton::BS_NORMAL,
313 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
314 IDR_AURA_WINDOW_CLOSE));
315
316 menu_button_ = new views::MenuButton(NULL, string16(), this, true);
317 menu_button_->set_border(NULL);
318
319 views::GridLayout* layout = new views::GridLayout(this);
320 SetLayoutManager(layout);
321
322 views::ColumnSet* columns = layout->AddColumnSet(0);
323
324 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal/2);
325
326 // Notification Icon.
327 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
328 0, /* resize percent */
329 views::GridLayout::FIXED,
330 kNotificationIconWidth, kNotificationIconWidth);
331
332 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal/2);
333
334 // Notification message text.
335 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
336 100, /* resize percent */
337 views::GridLayout::USE_PREF, 0, 0);
338
339 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal/2);
340
341 // Close and menu buttons.
342 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
343 0, /* resize percent */
344 views::GridLayout::FIXED,
345 kWebNotificationButtonWidth,
346 kWebNotificationButtonWidth);
347
348 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal/2);
349
350 // Layout rows
351 layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems);
352
353 layout->StartRow(0, 0);
354 layout->AddView(icon_, 1, 2);
355 layout->AddView(message_view, 1, 2);
356 layout->AddView(close_button_);
357
358 layout->StartRow(0, 0);
359 layout->SkipColumns(4);
360 layout->AddView(menu_button_);
361
362 layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems);
363 }
364
365 // Overridden from ButtonListener.
366 virtual void ButtonPressed(views::Button* sender,
367 const views::Event& event) OVERRIDE {
368 if (sender == close_button_)
369 tray_->RemoveNotification(notification_.id);
370 }
371
372 // Overridden from MenuButtonListener.
373 virtual void OnMenuButtonClicked(View* source, const gfx::Point& point) {
374 if (source != menu_button_)
375 return;
376 WebNotificationMenuModel menu_model(tray_, notification_);
377 views::MenuModelAdapter menu_model_adapter(&menu_model);
378 views::MenuRunner menu_runner(menu_model_adapter.CreateMenu());
379
380 gfx::Point screen_location;
381 views::View::ConvertPointToScreen(menu_button_, &screen_location);
382 ignore_result(menu_runner.RunMenuAt(
383 source->GetWidget()->GetTopLevelWidget(),
384 menu_button_,
385 gfx::Rect(screen_location, menu_button_->size()),
386 views::MenuItemView::TOPRIGHT,
387 views::MenuRunner::HAS_MNEMONICS));
388 }
389
390
391 private:
392 WebNotificationTray* tray_;
393 WebNotification notification_;
394 views::ImageView* icon_;
395 views::MenuButton* menu_button_;
396 views::ImageButton* close_button_;
397
398 DISALLOW_COPY_AND_ASSIGN(WebNotificationView);
399 };
400
401 } // namespace internal
402
403 using internal::WebNotificationList;
404 using internal::WebNotificationView;
405
406 class WebNotificationTray::BubbleContentsView : public views::View {
407 public:
408 explicit BubbleContentsView(WebNotificationTray* tray)
409 : tray_(tray) {
410 SetLayoutManager(new views::FillLayout);
411 set_background(views::Background::CreateSolidBackground(kBackgroundColor));
412
413 scroll_content_ = new views::View;
414 scroll_content_->SetLayoutManager(
415 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
416 scroller_ = new internal::FixedSizedScrollView;
417 scroller_->SetContentsView(scroll_content_);
418
419 AddChildView(scroller_);
420 }
421
422 void Update(const WebNotificationList::Notifications& notifications) {
423 scroll_content_->RemoveAllChildViews(true);
424 for (WebNotificationList::Notifications::const_iterator iter =
425 notifications.begin(); iter != notifications.end(); ++iter) {
426 WebNotificationView* view = new WebNotificationView(tray_, *iter);
427 scroll_content_->AddChildView(view);
428 }
429 scroller_->Layout();
430 SizeToPreferredSize();
431 Layout();
432 PreferredSizeChanged();
433 SchedulePaint();
434 }
435
436 // views::View overrides.
437 virtual gfx::Size GetPreferredSize() {
438 gfx::Size preferred_size = scroll_content_->GetPreferredSize();
439 int height = std::min(
440 std::max(preferred_size.height(), kWebNotificationBubbleMinHeight),
441 kWebNotificationBubbleMaxHeight);
442 preferred_size.set_height(height);
443 return preferred_size;
444 }
445
446 private:
447 WebNotificationTray* tray_;
448 internal::FixedSizedScrollView* scroller_;
449 views::View* scroll_content_;
450
451 DISALLOW_COPY_AND_ASSIGN(BubbleContentsView);
452 };
453
454 class WebNotificationTray::Bubble
455 : public internal::SystemTrayBubbleView::Host {
456 public:
457 explicit Bubble(WebNotificationTray* tray) : tray_(tray),
458 bubble_view_(NULL),
459 bubble_widget_(NULL),
460 contents_view_(NULL) {
461 views::View* anchor = tray->tray_container();
462 views::BubbleBorder::ArrowLocation arrow_location;
463 int arrow_offset = 0;
464 if (tray_->shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) {
465 arrow_location = views::BubbleBorder::BOTTOM_RIGHT;
466 arrow_offset = anchor->GetContentsBounds().width() / 2;
467 } else if (tray_->shelf_alignment() == SHELF_ALIGNMENT_LEFT) {
468 arrow_location = views::BubbleBorder::LEFT_BOTTOM;
469 } else {
470 arrow_location = views::BubbleBorder::RIGHT_BOTTOM;
471 }
472 bubble_view_ = new internal::SystemTrayBubbleView(
473 anchor, arrow_location, this, false);
474 bubble_view_->SetMaxHeight(kWebNotificationBubbleMaxHeight);
475 bubble_view_->set_bubble_width(kWebNotificationWidth);
476
477 bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_);
478
479 bubble_view_->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
480 bubble_widget_->non_client_view()->frame_view()->set_background(NULL);
481 bubble_view_->SetBubbleBorder(arrow_offset);
482
483 contents_view_ = new BubbleContentsView(tray);
484 bubble_view_->AddChildView(contents_view_);
485
486 Update();
487 bubble_view_->Show();
488 }
489
490 virtual ~Bubble() {
491 if (bubble_view_)
492 bubble_view_->reset_host();
493 if (bubble_widget_)
494 bubble_widget_->Close();
495 }
496
497 // Overridden from SystemTrayBubbleView::Host.
498 virtual void BubbleViewDestroyed() OVERRIDE {
499 }
500
501 virtual gfx::Rect GetAnchorRect() const OVERRIDE {
502 gfx::Rect anchor_rect = tray_->tray_container()->GetScreenBounds();
503 return anchor_rect;
504 }
505
506 virtual void OnMouseEnteredView() OVERRIDE {
507 }
508
509 virtual void OnMouseExitedView() OVERRIDE {
510 }
511
512 void Update() {
513 contents_view_->Update(tray_->notification_list()->notifications());
514 bubble_view_->Layout();
515 bubble_view_->SchedulePaint();
516 }
517
518 views::Widget* bubble_widget() const { return bubble_widget_; }
519
520 private:
521 WebNotificationTray* tray_;
522 internal::SystemTrayBubbleView* bubble_view_;
523 views::Widget* bubble_widget_;
524 BubbleContentsView* contents_view_;
525 };
526
527 WebNotificationTray::WebNotificationTray(
528 internal::StatusAreaWidget* status_area_widget)
529 : status_area_widget_(status_area_widget),
530 notification_list_(new WebNotificationList()),
531 tray_container_(NULL),
532 icon_(NULL),
533 delegate_(NULL) {
534 tray_container_ = new views::View;
535 tray_container_->set_border(views::Border::CreateEmptyBorder(
536 kIconBorder, kIconBorder, kIconBorder, kIconBorder));
537 SetShelfAlignment(shelf_alignment());
538
539 icon_ = new views::ImageView;
540 tray_container_->AddChildView(icon_);
541 UpdateIcon(); // Hides the tray initially.
542
543 SetContents(tray_container_);
544
545 Shell::GetInstance()->AddEnvEventFilter(this);
546 }
547
548 WebNotificationTray::~WebNotificationTray() {
549 Shell::GetInstance()->RemoveEnvEventFilter(this);
550 }
551
552 void WebNotificationTray::SetDelegate(Delegate* delegate) {
553 DCHECK(!delegate_);
554 delegate_ = delegate;
555 }
556
557 void WebNotificationTray::AddNotification(const std::string& id,
558 const string16& title,
559 const string16& message,
560 const string16& source,
561 const std::string& extension) {
562 notification_list_->AddNotification(id, title, message, source, extension);
563 UpdateIcon();
564 if (bubble()) {
565 bubble_->Update();
566 } else {
567 status_area_widget_->ShowWebNotificationBubble(
568 internal::StatusAreaWidget::NON_USER_ACTION);
569 }
570 }
571
572 void WebNotificationTray::RemoveNotification(const std::string& id) {
573 if (!notification_list_->RemoveNotification(id))
574 return;
575 if (delegate_)
576 delegate_->NotificationRemoved(id);
577 UpdateBubbleAndIcon();
578 }
579
580 void WebNotificationTray::SetNotificationImage(const std::string& id,
581 const SkBitmap& image) {
582 if (!notification_list_->SetNotificationImage(id, image))
583 return;
584 if (bubble())
585 bubble_->Update();
586 }
587
588 void WebNotificationTray::DisableByExtension(const std::string& id) {
589 notification_list_->RemoveNotificationsByExtension(id);
590 UpdateBubbleAndIcon();
591 if (delegate_)
592 delegate_->DisableExtension(id);
593 }
594
595 void WebNotificationTray::DisableByUrl(const std::string& id) {
596 notification_list_->RemoveNotificationsBySource(id);
597 UpdateBubbleAndIcon();
598 if (delegate_)
599 delegate_->DisableNotificationsFromSource(id);
600 }
601
602 void WebNotificationTray::ShowBubble() {
603 if (bubble())
604 return;
605 bubble_.reset(new Bubble(this));
606 }
607
608 void WebNotificationTray::HideBubble() {
609 bubble_.reset();
610 }
611
612 void WebNotificationTray::ShowSettings(const std::string& id) {
613 if (delegate_)
614 delegate_->ShowSettings(id);
615 }
616
617 bool WebNotificationTray::PreHandleKeyEvent(aura::Window* target,
618 aura::KeyEvent* event) {
619 return false;
620 }
621
622 bool WebNotificationTray::PreHandleMouseEvent(aura::Window* target,
623 aura::MouseEvent* event) {
624 if (event->type() == ui::ET_MOUSE_PRESSED)
625 ProcessLocatedEvent(*event);
626 return false;
627 }
628
629 ui::TouchStatus WebNotificationTray::PreHandleTouchEvent(aura::Window* target,
630 aura::TouchEvent* event) {
631 if (event->type() == ui::ET_TOUCH_PRESSED)
632 ProcessLocatedEvent(*event);
633 return ui::TOUCH_STATUS_UNKNOWN;
634 }
635
636 ui::GestureStatus WebNotificationTray::PreHandleGestureEvent(
637 aura::Window* target,
638 aura::GestureEvent* event) {
639 return ui::GESTURE_STATUS_UNKNOWN;
640 }
641
642 void WebNotificationTray::SetShelfAlignment(ShelfAlignment alignment) {
643 internal::TrayBackgroundView::SetShelfAlignment(alignment);
644 tray_container_->SetLayoutManager(new views::BoxLayout(
645 alignment == SHELF_ALIGNMENT_BOTTOM ?
646 views::BoxLayout::kHorizontal : views::BoxLayout::kVertical,
647 0, 0, 0));
648 }
649
650 bool WebNotificationTray::PerformAction(const views::Event& event) {
651 if (bubble()) {
652 status_area_widget_->HideWebNotificationBubble();
653 } else {
654 status_area_widget_->ShowWebNotificationBubble(
655 internal::StatusAreaWidget::USER_ACTION);
656 }
657 return true;
658 }
659
660 int WebNotificationTray::GetNotificationCount() const {
661 return notification_list()->notifications().size();
662 }
663
664 void WebNotificationTray::UpdateIcon() {
665 int count = GetNotificationCount();
666 if (count == 0) {
667 SetVisible(false);
668 } else {
669 icon_->SetImage(GetNotificationImage(count));
670 SetVisible(true);
671 }
672 PreferredSizeChanged();
673 }
674
675 void WebNotificationTray::UpdateBubbleAndIcon() {
676 UpdateIcon();
677 if (!bubble())
678 return;
679 if (GetNotificationCount() == 0)
680 status_area_widget_->HideWebNotificationBubble();
681 else
682 bubble_->Update();
683 }
684
685 void WebNotificationTray::ProcessLocatedEvent(const aura::LocatedEvent& event) {
686 if (!bubble())
687 return;
688 gfx::Rect bounds =
689 bubble_->bubble_widget()->GetNativeWindow()->GetBoundsInRootWindow();
690 if (!bounds.Contains(event.root_location()))
691 status_area_widget_->HideWebNotificationBubble();
692 }
693
694 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/web_notification/web_notification_tray.h ('k') | ash/system/web_notification/web_notification_tray_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698