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/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shelf/shelf_layout_manager_observer.h"
11 #include "ash/shelf/shelf_widget.h"
12 #include "ash/shell.h"
13 #include "ash/shell_window_ids.h"
14 #include "ash/system/status_area_widget.h"
15 #include "ash/system/tray/system_tray.h"
16 #include "ash/system/tray/tray_background_view.h"
17 #include "ash/system/tray/tray_bubble_wrapper.h"
18 #include "ash/system/tray/tray_constants.h"
19 #include "ash/system/tray/tray_utils.h"
20 #include "base/auto_reset.h"
21 #include "base/i18n/number_formatting.h"
22 #include "base/i18n/rtl.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "grit/ash_strings.h"
25 #include "grit/ui_strings.h"
26 #include "ui/aura/root_window.h"
27 #include "ui/aura/window.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/gfx/screen.h"
30 #include "ui/message_center/message_center_style.h"
31 #include "ui/message_center/message_center_tray_delegate.h"
32 #include "ui/message_center/message_center_util.h"
33 #include "ui/message_center/views/message_bubble_base.h"
34 #include "ui/message_center/views/message_center_bubble.h"
35 #include "ui/message_center/views/message_popup_collection.h"
36 #include "ui/views/bubble/tray_bubble_view.h"
37 #include "ui/views/controls/button/custom_button.h"
38 #include "ui/views/controls/image_view.h"
39 #include "ui/views/controls/label.h"
40 #include "ui/views/controls/menu/menu_runner.h"
41 #include "ui/views/layout/fill_layout.h"
42
43 #if defined(OS_CHROMEOS)
44
45 namespace message_center {
46
CreateMessageCenterTray()47 MessageCenterTrayDelegate* CreateMessageCenterTray() {
48 // On Windows+Ash the Tray will not be hosted in ash::Shell.
49 NOTREACHED();
50 return NULL;
51 }
52
53 } // namespace message_center
54
55 #endif // defined(OS_CHROMEOS)
56
57 namespace ash {
58 namespace {
59
60 // Menu commands
61 const int kToggleQuietMode = 0;
62 const int kEnableQuietModeDay = 2;
63
64 }
65
66 namespace internal {
67 namespace {
68
69 const SkColor kWebNotificationColorNoUnread = SkColorSetA(SK_ColorWHITE, 128);
70 const SkColor kWebNotificationColorWithUnread = SK_ColorWHITE;
71
72 }
73
74 // Observes the change of work area (including temporary change by auto-hide)
75 // and notifies MessagePopupCollection.
76 class WorkAreaObserver : public ShelfLayoutManagerObserver,
77 public ShellObserver {
78 public:
79 WorkAreaObserver();
80 virtual ~WorkAreaObserver();
81
82 void SetSystemTrayHeight(int height);
83
84 // Starts observing |shelf| and shell and sends the change to |collection|.
85 void StartObserving(message_center::MessagePopupCollection* collection,
86 aura::Window* root_window);
87
88 // Stops the observing session.
89 void StopObserving();
90
91 // Overridden from ShellObserver:
92 virtual void OnDisplayWorkAreaInsetsChanged() OVERRIDE;
93
94 // Overridden from ShelfLayoutManagerObserver:
95 virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) OVERRIDE;
96
97 private:
98 // Updates |shelf_| from |root_window_|.
99 void UpdateShelf();
100
101 message_center::MessagePopupCollection* collection_;
102 aura::Window* root_window_;
103 ShelfLayoutManager* shelf_;
104 int system_tray_height_;
105
106 DISALLOW_COPY_AND_ASSIGN(WorkAreaObserver);
107 };
108
WorkAreaObserver()109 WorkAreaObserver::WorkAreaObserver()
110 : collection_(NULL),
111 root_window_(NULL),
112 shelf_(NULL),
113 system_tray_height_(0) {
114 }
115
~WorkAreaObserver()116 WorkAreaObserver::~WorkAreaObserver() {
117 StopObserving();
118 }
119
SetSystemTrayHeight(int height)120 void WorkAreaObserver::SetSystemTrayHeight(int height) {
121 system_tray_height_ = height;
122
123 // If the shelf is shown during auto-hide state, the distance from the edge
124 // should be reduced by the height of shelf's shown height.
125 if (shelf_ && shelf_->visibility_state() == SHELF_AUTO_HIDE &&
126 shelf_->auto_hide_state() == SHELF_AUTO_HIDE_SHOWN) {
127 system_tray_height_ -= ShelfLayoutManager::GetPreferredShelfSize() -
128 ShelfLayoutManager::kAutoHideSize;
129 }
130
131 if (system_tray_height_ > 0 && ash::switches::UseAlternateShelfLayout())
132 system_tray_height_ += message_center::kMarginBetweenItems;
133
134 if (!shelf_)
135 return;
136
137 OnAutoHideStateChanged(shelf_->auto_hide_state());
138 }
139
StartObserving(message_center::MessagePopupCollection * collection,aura::Window * root_window)140 void WorkAreaObserver::StartObserving(
141 message_center::MessagePopupCollection* collection,
142 aura::Window* root_window) {
143 DCHECK(collection);
144 collection_ = collection;
145 root_window_ = root_window;
146 UpdateShelf();
147 Shell::GetInstance()->AddShellObserver(this);
148 if (system_tray_height_ > 0)
149 OnAutoHideStateChanged(shelf_->auto_hide_state());
150 }
151
StopObserving()152 void WorkAreaObserver::StopObserving() {
153 Shell::GetInstance()->RemoveShellObserver(this);
154 if (shelf_)
155 shelf_->RemoveObserver(this);
156 collection_ = NULL;
157 shelf_ = NULL;
158 }
159
OnDisplayWorkAreaInsetsChanged()160 void WorkAreaObserver::OnDisplayWorkAreaInsetsChanged() {
161 UpdateShelf();
162
163 collection_->OnDisplayBoundsChanged(
164 Shell::GetScreen()->GetDisplayNearestWindow(
165 shelf_->shelf_widget()->GetNativeView()));
166 }
167
OnAutoHideStateChanged(ShelfAutoHideState new_state)168 void WorkAreaObserver::OnAutoHideStateChanged(ShelfAutoHideState new_state) {
169 gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
170 shelf_->shelf_widget()->GetNativeView());
171 gfx::Rect work_area = display.work_area();
172 int width = 0;
173 if ((shelf_->visibility_state() == SHELF_AUTO_HIDE) &&
174 new_state == SHELF_AUTO_HIDE_SHOWN) {
175 // Since the work_area is already reduced by kAutoHideSize, the inset width
176 // should be just the difference.
177 width = ShelfLayoutManager::GetPreferredShelfSize() -
178 ShelfLayoutManager::kAutoHideSize;
179 }
180 work_area.Inset(shelf_->SelectValueForShelfAlignment(
181 gfx::Insets(0, 0, width, 0),
182 gfx::Insets(0, width, 0, 0),
183 gfx::Insets(0, 0, 0, width),
184 gfx::Insets(width, 0, 0, 0)));
185 if (system_tray_height_ > 0) {
186 work_area.set_height(
187 std::max(0, work_area.height() - system_tray_height_));
188 if (shelf_->GetAlignment() == SHELF_ALIGNMENT_TOP)
189 work_area.set_y(work_area.y() + system_tray_height_);
190 }
191 collection_->SetDisplayInfo(work_area, display.bounds());
192 }
193
UpdateShelf()194 void WorkAreaObserver::UpdateShelf() {
195 if (shelf_)
196 return;
197
198 shelf_ = ShelfLayoutManager::ForLauncher(root_window_);
199 if (shelf_)
200 shelf_->AddObserver(this);
201 }
202
203 // Class to initialize and manage the WebNotificationBubble and
204 // TrayBubbleWrapper instances for a bubble.
205 class WebNotificationBubbleWrapper {
206 public:
207 // Takes ownership of |bubble| and creates |bubble_wrapper_|.
WebNotificationBubbleWrapper(WebNotificationTray * tray,message_center::MessageBubbleBase * bubble)208 WebNotificationBubbleWrapper(WebNotificationTray* tray,
209 message_center::MessageBubbleBase* bubble) {
210 bubble_.reset(bubble);
211 views::TrayBubbleView::AnchorAlignment anchor_alignment =
212 tray->GetAnchorAlignment();
213 views::TrayBubbleView::InitParams init_params =
214 bubble->GetInitParams(anchor_alignment);
215 views::View* anchor = tray->tray_container();
216 if (anchor_alignment == views::TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
217 gfx::Point bounds(anchor->width() / 2, 0);
218 views::View::ConvertPointToWidget(anchor, &bounds);
219 init_params.arrow_offset = bounds.x();
220 }
221 views::TrayBubbleView* bubble_view = views::TrayBubbleView::Create(
222 tray->GetBubbleWindowContainer(), anchor, tray, &init_params);
223 if (ash::switches::UseAlternateShelfLayout())
224 bubble_view->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
225 bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_view));
226 bubble->InitializeContents(bubble_view);
227 }
228
bubble() const229 message_center::MessageBubbleBase* bubble() const { return bubble_.get(); }
230
231 // Convenience accessors.
bubble_view() const232 views::TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
233
234 private:
235 scoped_ptr<message_center::MessageBubbleBase> bubble_;
236 scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
237
238 DISALLOW_COPY_AND_ASSIGN(WebNotificationBubbleWrapper);
239 };
240
241 class WebNotificationButton : public views::CustomButton {
242 public:
WebNotificationButton(views::ButtonListener * listener)243 WebNotificationButton(views::ButtonListener* listener)
244 : views::CustomButton(listener),
245 is_bubble_visible_(false),
246 unread_count_(0) {
247 SetLayoutManager(new views::FillLayout);
248 unread_label_ = new views::Label();
249 SetupLabelForTray(unread_label_);
250 AddChildView(unread_label_);
251 }
252
SetBubbleVisible(bool visible)253 void SetBubbleVisible(bool visible) {
254 if (visible == is_bubble_visible_)
255 return;
256
257 is_bubble_visible_ = visible;
258 UpdateIconVisibility();
259 }
260
SetUnreadCount(int unread_count)261 void SetUnreadCount(int unread_count) {
262 // base::FormatNumber doesn't convert to arabic numeric characters.
263 // TODO(mukai): use ICU to support conversion for such locales.
264 unread_count_ = unread_count;
265 // TODO(mukai): move NINE_PLUS message to ui_strings, it doesn't need to be
266 // in ash_strings.
267 unread_label_->SetText((unread_count > 9) ?
268 l10n_util::GetStringUTF16(IDS_ASH_NOTIFICATION_UNREAD_COUNT_NINE_PLUS) :
269 base::FormatNumber(unread_count));
270 UpdateIconVisibility();
271 }
272
273 protected:
274 // Overridden from views::ImageButton:
GetPreferredSize()275 virtual gfx::Size GetPreferredSize() OVERRIDE {
276 const int notification_item_size = GetShelfItemHeight();
277 return gfx::Size(notification_item_size, notification_item_size);
278 }
279
GetHeightForWidth(int width)280 virtual int GetHeightForWidth(int width) OVERRIDE {
281 return GetPreferredSize().height();
282 }
283
284 private:
UpdateIconVisibility()285 void UpdateIconVisibility() {
286 unread_label_->SetEnabledColor(
287 (!is_bubble_visible_ && unread_count_ > 0) ?
288 kWebNotificationColorWithUnread : kWebNotificationColorNoUnread);
289 SchedulePaint();
290 }
291
292 bool is_bubble_visible_;
293 int unread_count_;
294
295 views::Label* unread_label_;
296
297 DISALLOW_COPY_AND_ASSIGN(WebNotificationButton);
298 };
299
300 } // namespace internal
301
WebNotificationTray(internal::StatusAreaWidget * status_area_widget)302 WebNotificationTray::WebNotificationTray(
303 internal::StatusAreaWidget* status_area_widget)
304 : TrayBackgroundView(status_area_widget),
305 button_(NULL),
306 show_message_center_on_unlock_(false),
307 should_update_tray_content_(false),
308 should_block_shelf_auto_hide_(false) {
309 button_ = new internal::WebNotificationButton(this);
310 button_->set_triggerable_event_flags(
311 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON);
312 tray_container()->AddChildView(button_);
313 SetContentsBackground();
314 tray_container()->set_border(NULL);
315 SetVisible(false);
316 message_center_tray_.reset(new message_center::MessageCenterTray(
317 this,
318 message_center::MessageCenter::Get()));
319 work_area_observer_.reset(new internal::WorkAreaObserver());
320 OnMessageCenterTrayChanged();
321 }
322
~WebNotificationTray()323 WebNotificationTray::~WebNotificationTray() {
324 // Release any child views that might have back pointers before ~View().
325 message_center_bubble_.reset();
326 popup_collection_.reset();
327 work_area_observer_.reset();
328 }
329
330 // Public methods.
331
ShowMessageCenterInternal(bool show_settings)332 bool WebNotificationTray::ShowMessageCenterInternal(bool show_settings) {
333 if (!ShouldShowMessageCenter())
334 return false;
335
336 should_block_shelf_auto_hide_ = true;
337 message_center::MessageCenterBubble* message_center_bubble =
338 new message_center::MessageCenterBubble(
339 message_center(),
340 message_center_tray_.get(),
341 ash::switches::UseAlternateShelfLayout());
342
343 int max_height = 0;
344 aura::Window* status_area_window = status_area_widget()->GetNativeView();
345 switch (GetShelfLayoutManager()->GetAlignment()) {
346 case SHELF_ALIGNMENT_BOTTOM: {
347 gfx::Rect shelf_bounds = GetShelfLayoutManager()->GetIdealBounds();
348 max_height = shelf_bounds.y();
349 break;
350 }
351 case SHELF_ALIGNMENT_TOP: {
352 aura::Window* root = status_area_window->GetRootWindow();
353 max_height =
354 root->bounds().height() - status_area_window->bounds().height();
355 break;
356 }
357 case SHELF_ALIGNMENT_LEFT:
358 case SHELF_ALIGNMENT_RIGHT: {
359 // Assume that the bottom line of the status area widget and the bubble
360 // are aligned.
361 max_height = status_area_window->GetBoundsInRootWindow().bottom();
362 break;
363 }
364 default:
365 NOTREACHED();
366 }
367
368 message_center_bubble->SetMaxHeight(std::max(0,
369 max_height - GetTraySpacing()));
370 if (show_settings)
371 message_center_bubble->SetSettingsVisible();
372 message_center_bubble_.reset(
373 new internal::WebNotificationBubbleWrapper(this, message_center_bubble));
374
375 status_area_widget()->SetHideSystemNotifications(true);
376 GetShelfLayoutManager()->UpdateAutoHideState();
377 button_->SetBubbleVisible(true);
378 SetDrawBackgroundAsActive(true);
379 return true;
380 }
381
ShowMessageCenter()382 bool WebNotificationTray::ShowMessageCenter() {
383 return ShowMessageCenterInternal(false /* show_settings */);
384 }
385
HideMessageCenter()386 void WebNotificationTray::HideMessageCenter() {
387 if (!message_center_bubble())
388 return;
389 SetDrawBackgroundAsActive(false);
390 message_center_bubble_.reset();
391 should_block_shelf_auto_hide_ = false;
392 show_message_center_on_unlock_ = false;
393 status_area_widget()->SetHideSystemNotifications(false);
394 GetShelfLayoutManager()->UpdateAutoHideState();
395 button_->SetBubbleVisible(false);
396 }
397
SetSystemTrayHeight(int height)398 void WebNotificationTray::SetSystemTrayHeight(int height) {
399 work_area_observer_->SetSystemTrayHeight(height);
400 }
401
ShowPopups()402 bool WebNotificationTray::ShowPopups() {
403 if (message_center_bubble())
404 return false;
405
406 popup_collection_.reset(new message_center::MessagePopupCollection(
407 ash::Shell::GetContainer(
408 GetWidget()->GetNativeView()->GetRootWindow(),
409 internal::kShellWindowId_StatusContainer),
410 message_center(),
411 message_center_tray_.get(),
412 ash::switches::UseAlternateShelfLayout()));
413 work_area_observer_->StartObserving(
414 popup_collection_.get(), GetWidget()->GetNativeView()->GetRootWindow());
415 return true;
416 }
417
HidePopups()418 void WebNotificationTray::HidePopups() {
419 DCHECK(popup_collection_.get());
420
421 popup_collection_->MarkAllPopupsShown();
422 popup_collection_.reset();
423 work_area_observer_->StopObserving();
424 }
425
426 // Private methods.
427
ShouldShowMessageCenter()428 bool WebNotificationTray::ShouldShowMessageCenter() {
429 return status_area_widget()->login_status() != user::LOGGED_IN_LOCKED &&
430 !(status_area_widget()->system_tray() &&
431 status_area_widget()->system_tray()->HasNotificationBubble());
432 }
433
ShouldBlockLauncherAutoHide() const434 bool WebNotificationTray::ShouldBlockLauncherAutoHide() const {
435 return should_block_shelf_auto_hide_;
436 }
437
IsMessageCenterBubbleVisible() const438 bool WebNotificationTray::IsMessageCenterBubbleVisible() const {
439 return (message_center_bubble() &&
440 message_center_bubble()->bubble()->IsVisible());
441 }
442
IsMouseInNotificationBubble() const443 bool WebNotificationTray::IsMouseInNotificationBubble() const {
444 return false;
445 }
446
ShowMessageCenterBubble()447 void WebNotificationTray::ShowMessageCenterBubble() {
448 if (!IsMessageCenterBubbleVisible())
449 message_center_tray_->ShowMessageCenterBubble();
450 }
451
UpdateAfterLoginStatusChange(user::LoginStatus login_status)452 void WebNotificationTray::UpdateAfterLoginStatusChange(
453 user::LoginStatus login_status) {
454 OnMessageCenterTrayChanged();
455 }
456
SetShelfAlignment(ShelfAlignment alignment)457 void WebNotificationTray::SetShelfAlignment(ShelfAlignment alignment) {
458 if (alignment == shelf_alignment())
459 return;
460 internal::TrayBackgroundView::SetShelfAlignment(alignment);
461 tray_container()->set_border(NULL);
462 // Destroy any existing bubble so that it will be rebuilt correctly.
463 message_center_tray_->HideMessageCenterBubble();
464 message_center_tray_->HidePopupBubble();
465 }
466
AnchorUpdated()467 void WebNotificationTray::AnchorUpdated() {
468 if (message_center_bubble()) {
469 message_center_bubble()->bubble_view()->UpdateBubble();
470 UpdateBubbleViewArrow(message_center_bubble()->bubble_view());
471 }
472 }
473
GetAccessibleNameForTray()474 base::string16 WebNotificationTray::GetAccessibleNameForTray() {
475 return l10n_util::GetStringUTF16(
476 IDS_MESSAGE_CENTER_ACCESSIBLE_NAME);
477 }
478
HideBubbleWithView(const views::TrayBubbleView * bubble_view)479 void WebNotificationTray::HideBubbleWithView(
480 const views::TrayBubbleView* bubble_view) {
481 if (message_center_bubble() &&
482 bubble_view == message_center_bubble()->bubble_view()) {
483 message_center_tray_->HideMessageCenterBubble();
484 } else if (popup_collection_.get()) {
485 message_center_tray_->HidePopupBubble();
486 }
487 }
488
PerformAction(const ui::Event & event)489 bool WebNotificationTray::PerformAction(const ui::Event& event) {
490 if (message_center_bubble())
491 message_center_tray_->HideMessageCenterBubble();
492 else
493 message_center_tray_->ShowMessageCenterBubble();
494 return true;
495 }
496
BubbleViewDestroyed()497 void WebNotificationTray::BubbleViewDestroyed() {
498 if (message_center_bubble())
499 message_center_bubble()->bubble()->BubbleViewDestroyed();
500 }
501
OnMouseEnteredView()502 void WebNotificationTray::OnMouseEnteredView() {}
503
OnMouseExitedView()504 void WebNotificationTray::OnMouseExitedView() {}
505
GetAccessibleNameForBubble()506 base::string16 WebNotificationTray::GetAccessibleNameForBubble() {
507 return GetAccessibleNameForTray();
508 }
509
GetAnchorRect(views::Widget * anchor_widget,views::TrayBubbleView::AnchorType anchor_type,views::TrayBubbleView::AnchorAlignment anchor_alignment)510 gfx::Rect WebNotificationTray::GetAnchorRect(
511 views::Widget* anchor_widget,
512 views::TrayBubbleView::AnchorType anchor_type,
513 views::TrayBubbleView::AnchorAlignment anchor_alignment) {
514 return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment);
515 }
516
HideBubble(const views::TrayBubbleView * bubble_view)517 void WebNotificationTray::HideBubble(const views::TrayBubbleView* bubble_view) {
518 HideBubbleWithView(bubble_view);
519 }
520
ShowNotifierSettings()521 bool WebNotificationTray::ShowNotifierSettings() {
522 if (message_center_bubble()) {
523 static_cast<message_center::MessageCenterBubble*>(
524 message_center_bubble()->bubble())->SetSettingsVisible();
525 return true;
526 }
527 return ShowMessageCenterInternal(true /* show_settings */);
528 }
529
GetMessageCenterTray()530 message_center::MessageCenterTray* WebNotificationTray::GetMessageCenterTray() {
531 return message_center_tray_.get();
532 }
533
IsCommandIdChecked(int command_id) const534 bool WebNotificationTray::IsCommandIdChecked(int command_id) const {
535 if (command_id != kToggleQuietMode)
536 return false;
537 return message_center()->IsQuietMode();
538 }
539
IsCommandIdEnabled(int command_id) const540 bool WebNotificationTray::IsCommandIdEnabled(int command_id) const {
541 return true;
542 }
543
GetAcceleratorForCommandId(int command_id,ui::Accelerator * accelerator)544 bool WebNotificationTray::GetAcceleratorForCommandId(
545 int command_id,
546 ui::Accelerator* accelerator) {
547 return false;
548 }
549
ExecuteCommand(int command_id,int event_flags)550 void WebNotificationTray::ExecuteCommand(int command_id, int event_flags) {
551 if (command_id == kToggleQuietMode) {
552 bool in_quiet_mode = message_center()->IsQuietMode();
553 message_center()->SetQuietMode(!in_quiet_mode);
554 return;
555 }
556 base::TimeDelta expires_in = command_id == kEnableQuietModeDay ?
557 base::TimeDelta::FromDays(1):
558 base::TimeDelta::FromHours(1);
559 message_center()->EnterQuietModeWithExpire(expires_in);
560 }
561
ButtonPressed(views::Button * sender,const ui::Event & event)562 void WebNotificationTray::ButtonPressed(views::Button* sender,
563 const ui::Event& event) {
564 DCHECK_EQ(button_, sender);
565 PerformAction(event);
566 }
567
OnMessageCenterTrayChanged()568 void WebNotificationTray::OnMessageCenterTrayChanged() {
569 // Do not update the tray contents directly. Multiple change events can happen
570 // consecutively, and calling Update in the middle of those events will show
571 // intermediate unread counts for a moment.
572 should_update_tray_content_ = true;
573 base::MessageLoop::current()->PostTask(
574 FROM_HERE,
575 base::Bind(&WebNotificationTray::UpdateTrayContent, AsWeakPtr()));
576 }
577
UpdateTrayContent()578 void WebNotificationTray::UpdateTrayContent() {
579 if (!should_update_tray_content_)
580 return;
581 should_update_tray_content_ = false;
582
583 message_center::MessageCenter* message_center =
584 message_center_tray_->message_center();
585 button_->SetUnreadCount(message_center->UnreadNotificationCount());
586 if (IsMessageCenterBubbleVisible())
587 button_->SetState(views::CustomButton::STATE_PRESSED);
588 else
589 button_->SetState(views::CustomButton::STATE_NORMAL);
590 SetVisible((status_area_widget()->login_status() != user::LOGGED_IN_NONE) &&
591 (status_area_widget()->login_status() != user::LOGGED_IN_LOCKED) &&
592 (message_center->NotificationCount() > 0));
593 Layout();
594 SchedulePaint();
595 }
596
ClickedOutsideBubble()597 bool WebNotificationTray::ClickedOutsideBubble() {
598 // Only hide the message center
599 if (!message_center_bubble())
600 return false;
601
602 message_center_tray_->HideMessageCenterBubble();
603 return true;
604 }
605
message_center() const606 message_center::MessageCenter* WebNotificationTray::message_center() const {
607 return message_center_tray_->message_center();
608 }
609
610 // Methods for testing
611
IsPopupVisible() const612 bool WebNotificationTray::IsPopupVisible() const {
613 return message_center_tray_->popups_visible();
614 }
615
616 message_center::MessageCenterBubble*
GetMessageCenterBubbleForTest()617 WebNotificationTray::GetMessageCenterBubbleForTest() {
618 if (!message_center_bubble())
619 return NULL;
620 return static_cast<message_center::MessageCenterBubble*>(
621 message_center_bubble()->bubble());
622 }
623
624 } // namespace ash
625