Implemented SystemUse24HourClockPolicyTest browser test.
[chromium-blink-merge.git] / ash / system / tray / system_tray.cc
blob942b15c0b49c8055d2a04f46be8e1ed7e20a7605
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.
5 #include "ash/system/tray/system_tray.h"
7 #include "ash/ash_switches.h"
8 #include "ash/metrics/user_metrics_recorder.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shell.h"
11 #include "ash/shell/panel_window.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/system/bluetooth/tray_bluetooth.h"
14 #include "ash/system/date/tray_date.h"
15 #include "ash/system/drive/tray_drive.h"
16 #include "ash/system/ime/tray_ime.h"
17 #include "ash/system/monitor/tray_monitor.h"
18 #include "ash/system/session_length_limit/tray_session_length_limit.h"
19 #include "ash/system/status_area_widget.h"
20 #include "ash/system/tray/system_tray_delegate.h"
21 #include "ash/system/tray/system_tray_item.h"
22 #include "ash/system/tray/tray_bubble_wrapper.h"
23 #include "ash/system/tray/tray_constants.h"
24 #include "ash/system/tray_accessibility.h"
25 #include "ash/system/tray_caps_lock.h"
26 #include "ash/system/tray_update.h"
27 #include "ash/system/user/login_status.h"
28 #include "ash/system/user/tray_user.h"
29 #include "ash/system/user/tray_user_separator.h"
30 #include "ash/system/web_notification/web_notification_tray.h"
31 #include "base/command_line.h"
32 #include "base/logging.h"
33 #include "base/strings/utf_string_conversions.h"
34 #include "base/timer/timer.h"
35 #include "grit/ash_strings.h"
36 #include "ui/aura/root_window.h"
37 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/compositor/layer.h"
39 #include "ui/events/event_constants.h"
40 #include "ui/gfx/canvas.h"
41 #include "ui/gfx/screen.h"
42 #include "ui/gfx/skia_util.h"
43 #include "ui/views/border.h"
44 #include "ui/views/controls/label.h"
45 #include "ui/views/layout/box_layout.h"
46 #include "ui/views/layout/fill_layout.h"
47 #include "ui/views/view.h"
49 #if defined(OS_CHROMEOS)
50 #include "ash/system/chromeos/audio/tray_audio.h"
51 #include "ash/system/chromeos/brightness/tray_brightness.h"
52 #include "ash/system/chromeos/enterprise/tray_enterprise.h"
53 #include "ash/system/chromeos/managed/tray_locally_managed_user.h"
54 #include "ash/system/chromeos/network/tray_network.h"
55 #include "ash/system/chromeos/network/tray_sms.h"
56 #include "ash/system/chromeos/network/tray_vpn.h"
57 #include "ash/system/chromeos/power/tray_power.h"
58 #include "ash/system/chromeos/screen_security/screen_capture_tray_item.h"
59 #include "ash/system/chromeos/screen_security/screen_share_tray_item.h"
60 #include "ash/system/chromeos/settings/tray_settings.h"
61 #include "ash/system/chromeos/tray_display.h"
62 #include "ash/system/chromeos/tray_tracing.h"
63 #include "ui/message_center/message_center.h"
64 #endif
66 using views::TrayBubbleView;
68 namespace ash {
70 // The minimum width of the system tray menu width.
71 const int kMinimumSystemTrayMenuWidth = 300;
73 namespace internal {
75 // Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper
76 // instances for a bubble.
78 class SystemBubbleWrapper {
79 public:
80 // Takes ownership of |bubble|.
81 explicit SystemBubbleWrapper(internal::SystemTrayBubble* bubble)
82 : bubble_(bubble),
83 is_persistent_(false) {
86 // Initializes the bubble view and creates |bubble_wrapper_|.
87 void InitView(TrayBackgroundView* tray,
88 views::View* anchor,
89 TrayBubbleView::InitParams* init_params,
90 bool is_persistent) {
91 DCHECK(anchor);
92 user::LoginStatus login_status =
93 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
94 bubble_->InitView(anchor, login_status, init_params);
95 bubble_wrapper_.reset(
96 new internal::TrayBubbleWrapper(tray, bubble_->bubble_view()));
97 if (ash::switches::UseAlternateShelfLayout()) {
98 // The system bubble should not have an arrow.
99 bubble_->bubble_view()->SetArrowPaintType(
100 views::BubbleBorder::PAINT_NONE);
102 is_persistent_ = is_persistent;
104 // If ChromeVox is enabled, focus the default item if no item is focused.
105 if (Shell::GetInstance()->accessibility_delegate()->
106 IsSpokenFeedbackEnabled()) {
107 bubble_->FocusDefaultIfNeeded();
111 // Convenience accessors:
112 SystemTrayBubble* bubble() const { return bubble_.get(); }
113 SystemTrayBubble::BubbleType bubble_type() const {
114 return bubble_->bubble_type();
116 TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
117 bool is_persistent() const { return is_persistent_; }
119 private:
120 scoped_ptr<internal::SystemTrayBubble> bubble_;
121 scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
122 bool is_persistent_;
124 DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper);
127 } // namespace internal
129 // SystemTray
131 using internal::SystemTrayBubble;
133 SystemTray::SystemTray(internal::StatusAreaWidget* status_area_widget)
134 : internal::TrayBackgroundView(status_area_widget),
135 items_(),
136 default_bubble_height_(0),
137 hide_notifications_(false),
138 full_system_tray_menu_(false),
139 tray_accessibility_(NULL),
140 tray_date_(NULL) {
141 SetContentsBackground();
144 SystemTray::~SystemTray() {
145 // Destroy any child views that might have back pointers before ~View().
146 system_bubble_.reset();
147 notification_bubble_.reset();
148 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
149 it != items_.end();
150 ++it) {
151 (*it)->DestroyTrayView();
155 void SystemTray::InitializeTrayItems(SystemTrayDelegate* delegate) {
156 internal::TrayBackgroundView::Initialize();
157 CreateItems(delegate);
160 void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
161 #if !defined(OS_WIN)
162 AddTrayItem(new internal::TraySessionLengthLimit(this));
163 // Create user items for each possible user.
164 ash::Shell* shell = ash::Shell::GetInstance();
165 int maximum_user_profiles =
166 shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers();
167 for (int i = 0; i < maximum_user_profiles; i++) {
168 internal::TrayUser* tray_user = new internal::TrayUser(this, i);
169 AddTrayItem(tray_user);
170 user_items_.push_back(tray_user);
172 if (maximum_user_profiles > 1) {
173 // Add a special double line separator between users and the rest of the
174 // menu if more then one user is logged in.
175 AddTrayItem(new internal::TrayUserSeparator(this));
177 #endif
179 tray_accessibility_ = new internal::TrayAccessibility(this);
180 tray_date_ = new internal::TrayDate(this);
182 #if defined(OS_CHROMEOS)
183 AddTrayItem(new internal::TrayEnterprise(this));
184 AddTrayItem(new internal::TrayLocallyManagedUser(this));
185 AddTrayItem(new internal::TrayIME(this));
186 AddTrayItem(tray_accessibility_);
187 AddTrayItem(new internal::TrayTracing(this));
188 AddTrayItem(
189 new internal::TrayPower(this, message_center::MessageCenter::Get()));
190 AddTrayItem(new internal::TrayNetwork(this));
191 AddTrayItem(new internal::TrayVPN(this));
192 AddTrayItem(new internal::TraySms(this));
193 AddTrayItem(new internal::TrayBluetooth(this));
194 AddTrayItem(new internal::TrayDrive(this));
195 AddTrayItem(new internal::TrayDisplay(this));
196 AddTrayItem(new internal::ScreenCaptureTrayItem(this));
197 AddTrayItem(new internal::ScreenShareTrayItem(this));
198 AddTrayItem(new internal::TrayAudio(this));
199 AddTrayItem(new internal::TrayBrightness(this));
200 AddTrayItem(new internal::TrayCapsLock(this));
201 AddTrayItem(new internal::TraySettings(this));
202 AddTrayItem(new internal::TrayUpdate(this));
203 AddTrayItem(tray_date_);
204 #elif defined(OS_WIN)
205 AddTrayItem(tray_accessibility_);
206 AddTrayItem(new internal::TrayUpdate(this));
207 AddTrayItem(tray_date_);
208 #elif defined(OS_LINUX)
209 AddTrayItem(new internal::TrayIME(this));
210 AddTrayItem(tray_accessibility_);
211 AddTrayItem(new internal::TrayBluetooth(this));
212 AddTrayItem(new internal::TrayDrive(this));
213 AddTrayItem(new internal::TrayCapsLock(this));
214 AddTrayItem(new internal::TrayUpdate(this));
215 AddTrayItem(tray_date_);
216 #endif
218 #if defined(OS_LINUX)
219 CommandLine* cmd = CommandLine::ForCurrentProcess();
220 if (cmd->HasSwitch(ash::switches::kAshEnableMemoryMonitor))
221 AddTrayItem(new internal::TrayMonitor(this));
222 #endif
224 SetVisible(ash::Shell::GetInstance()->system_tray_delegate()->
225 GetTrayVisibilityOnStartup());
228 void SystemTray::AddTrayItem(SystemTrayItem* item) {
229 items_.push_back(item);
231 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
232 views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus());
233 item->UpdateAfterShelfAlignmentChange(shelf_alignment());
235 if (tray_item) {
236 tray_container()->AddChildViewAt(tray_item, 0);
237 PreferredSizeChanged();
238 tray_item_map_[item] = tray_item;
242 void SystemTray::RemoveTrayItem(SystemTrayItem* item) {
243 NOTIMPLEMENTED();
246 const std::vector<SystemTrayItem*>& SystemTray::GetTrayItems() const {
247 return items_.get();
250 const std::vector<internal::TrayUser*>& SystemTray::GetTrayUserItems() const {
251 return user_items_;
254 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) {
255 ShowDefaultViewWithOffset(
256 creation_type,
257 TrayBubbleView::InitParams::kArrowDefaultOffset,
258 false);
261 void SystemTray::ShowPersistentDefaultView() {
262 ShowItems(items_.get(),
263 false,
264 false,
265 BUBBLE_CREATE_NEW,
266 TrayBubbleView::InitParams::kArrowDefaultOffset,
267 true);
270 void SystemTray::ShowDetailedView(SystemTrayItem* item,
271 int close_delay,
272 bool activate,
273 BubbleCreationType creation_type) {
274 std::vector<SystemTrayItem*> items;
275 items.push_back(item);
276 ShowItems(items, true, activate, creation_type, GetTrayXOffset(item), false);
277 if (system_bubble_)
278 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
281 void SystemTray::SetDetailedViewCloseDelay(int close_delay) {
282 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED))
283 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
286 void SystemTray::HideDetailedView(SystemTrayItem* item) {
287 if (item != detailed_item_)
288 return;
289 DestroySystemBubble();
290 UpdateNotificationBubble();
293 void SystemTray::ShowNotificationView(SystemTrayItem* item) {
294 if (std::find(notification_items_.begin(), notification_items_.end(), item)
295 != notification_items_.end())
296 return;
297 notification_items_.push_back(item);
298 UpdateNotificationBubble();
301 void SystemTray::HideNotificationView(SystemTrayItem* item) {
302 std::vector<SystemTrayItem*>::iterator found_iter =
303 std::find(notification_items_.begin(), notification_items_.end(), item);
304 if (found_iter == notification_items_.end())
305 return;
306 notification_items_.erase(found_iter);
307 // Only update the notification bubble if visible (i.e. don't create one).
308 if (notification_bubble_)
309 UpdateNotificationBubble();
312 void SystemTray::UpdateAfterLoginStatusChange(user::LoginStatus login_status) {
313 DestroySystemBubble();
314 UpdateNotificationBubble();
316 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
317 it != items_.end();
318 ++it) {
319 (*it)->UpdateAfterLoginStatusChange(login_status);
322 // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial
323 // position of the shelf differs.
324 if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM)
325 UpdateAfterShelfAlignmentChange(shelf_alignment());
327 SetVisible(true);
328 PreferredSizeChanged();
331 void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
332 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
333 it != items_.end();
334 ++it) {
335 (*it)->UpdateAfterShelfAlignmentChange(alignment);
339 void SystemTray::SetHideNotifications(bool hide_notifications) {
340 if (notification_bubble_)
341 notification_bubble_->bubble()->SetVisible(!hide_notifications);
342 hide_notifications_ = hide_notifications;
345 bool SystemTray::ShouldShowShelf() const {
346 return system_bubble_.get() && system_bubble_->bubble()->ShouldShowShelf();
349 bool SystemTray::HasSystemBubble() const {
350 return system_bubble_.get() != NULL;
353 bool SystemTray::HasNotificationBubble() const {
354 return notification_bubble_.get() != NULL;
357 internal::SystemTrayBubble* SystemTray::GetSystemBubble() {
358 if (!system_bubble_)
359 return NULL;
360 return system_bubble_->bubble();
363 bool SystemTray::IsAnyBubbleVisible() const {
364 return ((system_bubble_.get() &&
365 system_bubble_->bubble()->IsVisible()) ||
366 (notification_bubble_.get() &&
367 notification_bubble_->bubble()->IsVisible()));
370 bool SystemTray::IsMouseInNotificationBubble() const {
371 if (!notification_bubble_)
372 return false;
373 return notification_bubble_->bubble_view()->GetBoundsInScreen().Contains(
374 Shell::GetScreen()->GetCursorScreenPoint());
377 bool SystemTray::CloseSystemBubble() const {
378 if (!system_bubble_)
379 return false;
380 system_bubble_->bubble()->Close();
381 return true;
384 views::View* SystemTray::GetHelpButtonView() const {
385 return tray_date_->GetHelpButtonView();
388 bool SystemTray::CloseNotificationBubbleForTest() const {
389 if (!notification_bubble_)
390 return false;
391 notification_bubble_->bubble()->Close();
392 return true;
395 // Private methods.
397 bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) {
398 DCHECK(type != SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
399 return system_bubble_.get() && system_bubble_->bubble_type() == type;
402 void SystemTray::DestroySystemBubble() {
403 CloseSystemBubbleAndDeactivateSystemTray();
404 detailed_item_ = NULL;
405 UpdateWebNotifications();
408 void SystemTray::DestroyNotificationBubble() {
409 if (notification_bubble_) {
410 notification_bubble_.reset();
411 UpdateWebNotifications();
415 int SystemTray::GetTrayXOffset(SystemTrayItem* item) const {
416 // Don't attempt to align the arrow if the shelf is on the left or right.
417 if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM &&
418 shelf_alignment() != SHELF_ALIGNMENT_TOP)
419 return TrayBubbleView::InitParams::kArrowDefaultOffset;
421 std::map<SystemTrayItem*, views::View*>::const_iterator it =
422 tray_item_map_.find(item);
423 if (it == tray_item_map_.end())
424 return TrayBubbleView::InitParams::kArrowDefaultOffset;
426 const views::View* item_view = it->second;
427 if (item_view->bounds().IsEmpty()) {
428 // The bounds of item could be still empty if it does not have a visible
429 // tray view. In that case, use the default (minimum) offset.
430 return TrayBubbleView::InitParams::kArrowDefaultOffset;
433 gfx::Point point(item_view->width() / 2, 0);
434 ConvertPointToWidget(item_view, &point);
435 return point.x();
438 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type,
439 int arrow_offset,
440 bool persistent) {
441 if (creation_type != BUBBLE_USE_EXISTING) {
442 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
443 ash::UMA_STATUS_AREA_MENU_OPENED);
445 ShowItems(items_.get(), false, true, creation_type, arrow_offset, persistent);
448 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
449 bool detailed,
450 bool can_activate,
451 BubbleCreationType creation_type,
452 int arrow_offset,
453 bool persistent) {
454 // No system tray bubbles in kiosk mode.
455 if (Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus() ==
456 ash::user::LOGGED_IN_KIOSK_APP) {
457 return;
460 // Destroy any existing bubble and create a new one.
461 SystemTrayBubble::BubbleType bubble_type = detailed ?
462 SystemTrayBubble::BUBBLE_TYPE_DETAILED :
463 SystemTrayBubble::BUBBLE_TYPE_DEFAULT;
465 // Destroy the notification bubble here so that it doesn't get rebuilt
466 // while we add items to the main bubble_ (e.g. in HideNotificationView).
467 notification_bubble_.reset();
468 if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) {
469 system_bubble_->bubble()->UpdateView(items, bubble_type);
470 // If ChromeVox is enabled, focus the default item if no item is focused.
471 if (Shell::GetInstance()->accessibility_delegate()->
472 IsSpokenFeedbackEnabled()) {
473 system_bubble_->bubble()->FocusDefaultIfNeeded();
475 } else {
476 // Remember if the menu is a single property (like e.g. volume) or the
477 // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case
478 // above, |full_system_tray_menu_| does not get changed since the fact that
479 // the menu is full (or not) doesn't change even if a "single property"
480 // (like network) replaces most of the menu.
481 full_system_tray_menu_ = items.size() > 1;
482 // The menu width is fixed, and it is a per language setting.
483 int menu_width = std::max(kMinimumSystemTrayMenuWidth,
484 Shell::GetInstance()->system_tray_delegate()->GetSystemTrayMenuWidth());
486 TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
487 GetAnchorAlignment(),
488 menu_width,
489 kTrayPopupMaxWidth);
490 init_params.can_activate = can_activate;
491 init_params.first_item_has_no_margin =
492 ash::switches::UseAlternateShelfLayout();
493 if (detailed) {
494 // This is the case where a volume control or brightness control bubble
495 // is created.
496 init_params.max_height = default_bubble_height_;
497 init_params.arrow_color = kBackgroundColor;
498 } else {
499 init_params.arrow_color = kHeaderBackgroundColor;
501 init_params.arrow_offset = arrow_offset;
502 if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)
503 init_params.close_on_deactivate = !persistent;
504 // For Volume and Brightness we don't want to show an arrow when
505 // they are shown in a bubble by themselves.
506 init_params.arrow_paint_type = views::BubbleBorder::PAINT_NORMAL;
507 if (items.size() == 1 && items[0]->ShouldHideArrow())
508 init_params.arrow_paint_type = views::BubbleBorder::PAINT_TRANSPARENT;
509 SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type);
510 system_bubble_.reset(new internal::SystemBubbleWrapper(bubble));
511 system_bubble_->InitView(this, tray_container(), &init_params, persistent);
513 // Save height of default view for creating detailed views directly.
514 if (!detailed)
515 default_bubble_height_ = system_bubble_->bubble_view()->height();
517 if (detailed && items.size() > 0)
518 detailed_item_ = items[0];
519 else
520 detailed_item_ = NULL;
522 UpdateNotificationBubble(); // State changed, re-create notifications.
523 if (!notification_bubble_)
524 UpdateWebNotifications();
525 GetShelfLayoutManager()->UpdateAutoHideState();
527 // When we show the system menu in our alternate shelf layout, we need to
528 // tint the background.
529 if (full_system_tray_menu_)
530 SetDrawBackgroundAsActive(true);
533 void SystemTray::UpdateNotificationBubble() {
534 // Only show the notification bubble if we have notifications.
535 if (notification_items_.empty()) {
536 DestroyNotificationBubble();
537 return;
539 // Destroy the existing bubble before constructing a new one.
540 notification_bubble_.reset();
541 SystemTrayBubble* notification_bubble;
542 notification_bubble = new SystemTrayBubble(
543 this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
544 views::View* anchor;
545 TrayBubbleView::AnchorType anchor_type;
546 // Tray items might want to show notifications while we are creating and
547 // initializing the |system_bubble_| - but it might not be fully initialized
548 // when coming here - this would produce a crashed like crbug.com/247416.
549 // As such we check the existence of the widget here.
550 if (system_bubble_.get() &&
551 system_bubble_->bubble_view() &&
552 system_bubble_->bubble_view()->GetWidget()) {
553 anchor = system_bubble_->bubble_view();
554 anchor_type = TrayBubbleView::ANCHOR_TYPE_BUBBLE;
555 } else {
556 anchor = tray_container();
557 anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY;
559 TrayBubbleView::InitParams init_params(anchor_type,
560 GetAnchorAlignment(),
561 kTrayPopupMinWidth,
562 kTrayPopupMaxWidth);
563 init_params.first_item_has_no_margin =
564 ash::switches::UseAlternateShelfLayout();
565 init_params.arrow_color = kBackgroundColor;
566 init_params.arrow_offset = GetTrayXOffset(notification_items_[0]);
567 notification_bubble_.reset(
568 new internal::SystemBubbleWrapper(notification_bubble));
569 notification_bubble_->InitView(this, anchor, &init_params, false);
571 if (notification_bubble->bubble_view()->child_count() == 0) {
572 // It is possible that none of the items generated actual notifications.
573 DestroyNotificationBubble();
574 return;
576 if (hide_notifications_)
577 notification_bubble->SetVisible(false);
578 else
579 UpdateWebNotifications();
582 void SystemTray::UpdateWebNotifications() {
583 TrayBubbleView* bubble_view = NULL;
584 if (notification_bubble_)
585 bubble_view = notification_bubble_->bubble_view();
586 else if (system_bubble_)
587 bubble_view = system_bubble_->bubble_view();
589 int height = 0;
590 if (bubble_view) {
591 gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
592 bubble_view->GetWidget()->GetNativeView()).work_area();
593 if (GetShelfLayoutManager()->GetAlignment() != SHELF_ALIGNMENT_TOP) {
594 height = std::max(
595 0, work_area.height() - bubble_view->GetBoundsInScreen().y());
596 } else {
597 height = std::max(
598 0, bubble_view->GetBoundsInScreen().bottom() - work_area.y());
601 status_area_widget()->web_notification_tray()->SetSystemTrayHeight(height);
604 void SystemTray::SetShelfAlignment(ShelfAlignment alignment) {
605 if (alignment == shelf_alignment())
606 return;
607 internal::TrayBackgroundView::SetShelfAlignment(alignment);
608 UpdateAfterShelfAlignmentChange(alignment);
609 // Destroy any existing bubble so that it is rebuilt correctly.
610 CloseSystemBubbleAndDeactivateSystemTray();
611 // Rebuild any notification bubble.
612 if (notification_bubble_) {
613 notification_bubble_.reset();
614 UpdateNotificationBubble();
618 void SystemTray::AnchorUpdated() {
619 if (notification_bubble_) {
620 notification_bubble_->bubble_view()->UpdateBubble();
621 // Ensure that the notification buble is above the shelf/status area.
622 notification_bubble_->bubble_view()->GetWidget()->StackAtTop();
623 UpdateBubbleViewArrow(notification_bubble_->bubble_view());
625 if (system_bubble_) {
626 system_bubble_->bubble_view()->UpdateBubble();
627 UpdateBubbleViewArrow(system_bubble_->bubble_view());
631 base::string16 SystemTray::GetAccessibleNameForTray() {
632 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
635 void SystemTray::BubbleResized(const TrayBubbleView* bubble_view) {
636 UpdateWebNotifications();
639 void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
640 if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) {
641 DestroySystemBubble();
642 UpdateNotificationBubble(); // State changed, re-create notifications.
643 GetShelfLayoutManager()->UpdateAutoHideState();
644 } else if (notification_bubble_.get() &&
645 bubble_view == notification_bubble_->bubble_view()) {
646 DestroyNotificationBubble();
650 bool SystemTray::ClickedOutsideBubble() {
651 if (!system_bubble_ || system_bubble_->is_persistent())
652 return false;
653 HideBubbleWithView(system_bubble_->bubble_view());
654 return true;
657 void SystemTray::BubbleViewDestroyed() {
658 if (system_bubble_) {
659 system_bubble_->bubble()->DestroyItemViews();
660 system_bubble_->bubble()->BubbleViewDestroyed();
664 void SystemTray::OnMouseEnteredView() {
665 if (system_bubble_)
666 system_bubble_->bubble()->StopAutoCloseTimer();
669 void SystemTray::OnMouseExitedView() {
670 if (system_bubble_)
671 system_bubble_->bubble()->RestartAutoCloseTimer();
674 base::string16 SystemTray::GetAccessibleNameForBubble() {
675 return GetAccessibleNameForTray();
678 gfx::Rect SystemTray::GetAnchorRect(
679 views::Widget* anchor_widget,
680 TrayBubbleView::AnchorType anchor_type,
681 TrayBubbleView::AnchorAlignment anchor_alignment) {
682 return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment);
685 void SystemTray::HideBubble(const TrayBubbleView* bubble_view) {
686 HideBubbleWithView(bubble_view);
689 views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) {
690 std::map<SystemTrayItem*, views::View*>::iterator it =
691 tray_item_map_.find(item);
692 return it == tray_item_map_.end() ? NULL : it->second;
695 void SystemTray::AddTrayUserItemForTest(internal::TrayUser* tray_user) {
696 AddTrayItem(tray_user);
697 user_items_.push_back(tray_user);
700 internal::TrayDate* SystemTray::GetTrayDateForTesting() const {
701 return tray_date_;
704 bool SystemTray::PerformAction(const ui::Event& event) {
705 // If we're already showing the default view, hide it; otherwise, show it
706 // (and hide any popup that's currently shown).
707 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) {
708 system_bubble_->bubble()->Close();
709 } else {
710 int arrow_offset = TrayBubbleView::InitParams::kArrowDefaultOffset;
711 if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) {
712 const ui::LocatedEvent& located_event =
713 static_cast<const ui::LocatedEvent&>(event);
714 if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM ||
715 shelf_alignment() == SHELF_ALIGNMENT_TOP) {
716 gfx::Point point(located_event.x(), 0);
717 ConvertPointToWidget(this, &point);
718 arrow_offset = point.x();
721 ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset, false);
723 return true;
726 void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() {
727 system_bubble_.reset();
728 // When closing a system bubble with the alternate shelf layout, we need to
729 // turn off the active tinting of the shelf.
730 if (full_system_tray_menu_) {
731 SetDrawBackgroundAsActive(false);
732 full_system_tray_menu_ = false;
736 } // namespace ash