Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / ash / system / tray / system_tray.cc
blob122253f998668651da7a6dbba6d808c7f71c4143
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/shelf/shelf_layout_manager.h"
9 #include "ash/shell.h"
10 #include "ash/shell/panel_window.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/system/bluetooth/tray_bluetooth.h"
13 #include "ash/system/brightness/tray_brightness.h"
14 #include "ash/system/chromeos/tray_tracing.h"
15 #include "ash/system/date/tray_date.h"
16 #include "ash/system/drive/tray_drive.h"
17 #include "ash/system/ime/tray_ime.h"
18 #include "ash/system/logout_button/tray_logout_button.h"
19 #include "ash/system/monitor/tray_monitor.h"
20 #include "ash/system/session_length_limit/tray_session_length_limit.h"
21 #include "ash/system/status_area_widget.h"
22 #include "ash/system/tray/system_tray_delegate.h"
23 #include "ash/system/tray/system_tray_item.h"
24 #include "ash/system/tray/tray_bubble_wrapper.h"
25 #include "ash/system/tray/tray_constants.h"
26 #include "ash/system/tray_accessibility.h"
27 #include "ash/system/tray_caps_lock.h"
28 #include "ash/system/tray_update.h"
29 #include "ash/system/user/login_status.h"
30 #include "ash/system/user/tray_user.h"
31 #include "ash/system/web_notification/web_notification_tray.h"
32 #include "base/command_line.h"
33 #include "base/logging.h"
34 #include "base/strings/utf_string_conversions.h"
35 #include "base/timer/timer.h"
36 #include "grit/ash_strings.h"
37 #include "ui/aura/root_window.h"
38 #include "ui/base/events/event_constants.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/compositor/layer.h"
41 #include "ui/gfx/canvas.h"
42 #include "ui/gfx/screen.h"
43 #include "ui/gfx/skia_util.h"
44 #include "ui/views/border.h"
45 #include "ui/views/controls/label.h"
46 #include "ui/views/layout/box_layout.h"
47 #include "ui/views/layout/fill_layout.h"
48 #include "ui/views/view.h"
50 #if defined(OS_CHROMEOS)
51 #include "ash/system/chromeos/audio/tray_audio.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 "ui/message_center/message_center.h"
63 #endif
65 using views::TrayBubbleView;
67 namespace ash {
69 // The minimum width of the system tray menu width.
70 const int kMinimumSystemTrayMenuWidth = 300;
72 namespace internal {
74 // Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper
75 // instances for a bubble.
77 class SystemBubbleWrapper {
78 public:
79 // Takes ownership of |bubble|.
80 explicit SystemBubbleWrapper(internal::SystemTrayBubble* bubble)
81 : bubble_(bubble) {
84 // Initializes the bubble view and creates |bubble_wrapper_|.
85 void InitView(TrayBackgroundView* tray,
86 views::View* anchor,
87 TrayBubbleView::InitParams* init_params) {
88 DCHECK(anchor);
89 user::LoginStatus login_status =
90 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
91 bubble_->InitView(anchor, login_status, init_params);
92 bubble_wrapper_.reset(
93 new internal::TrayBubbleWrapper(tray, bubble_->bubble_view()));
94 if (ash::switches::UseAlternateShelfLayout()) {
95 // The system bubble should not have an arrow.
96 bubble_->bubble_view()->SetArrowPaintType(
97 views::BubbleBorder::PAINT_NONE);
101 // Convenience accessors:
102 SystemTrayBubble* bubble() const { return bubble_.get(); }
103 SystemTrayBubble::BubbleType bubble_type() const {
104 return bubble_->bubble_type();
106 TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
108 private:
109 scoped_ptr<internal::SystemTrayBubble> bubble_;
110 scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
112 DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper);
115 } // namespace internal
117 // SystemTray
119 using internal::SystemTrayBubble;
121 SystemTray::SystemTray(internal::StatusAreaWidget* status_area_widget)
122 : internal::TrayBackgroundView(status_area_widget),
123 items_(),
124 default_bubble_height_(0),
125 hide_notifications_(false),
126 full_system_tray_menu_(false),
127 tray_accessibility_(NULL) {
128 SetContentsBackground();
131 SystemTray::~SystemTray() {
132 // Destroy any child views that might have back pointers before ~View().
133 system_bubble_.reset();
134 notification_bubble_.reset();
135 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
136 it != items_.end();
137 ++it) {
138 (*it)->DestroyTrayView();
142 void SystemTray::InitializeTrayItems(SystemTrayDelegate* delegate) {
143 internal::TrayBackgroundView::Initialize();
144 CreateItems(delegate);
147 void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
148 #if !defined(OS_WIN)
149 AddTrayItem(new internal::TraySessionLengthLimit(this));
150 AddTrayItem(new internal::TrayLogoutButton(this));
151 // In multi-profile user mode we can have multiple user tiles.
152 ash::Shell* shell = ash::Shell::GetInstance();
153 int maximum_user_profiles =
154 shell->delegate()->IsMultiProfilesEnabled() ?
155 shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() :
157 // Note: We purposely use one more item then logged in users to account for
158 // the additional separator.
159 for (int i = 0; i <= maximum_user_profiles; i++)
160 AddTrayItem(new internal::TrayUser(this, i));
162 #endif
163 #if defined(OS_CHROMEOS)
164 AddTrayItem(new internal::TrayEnterprise(this));
165 AddTrayItem(new internal::TrayLocallyManagedUser(this));
166 #endif
167 AddTrayItem(new internal::TrayIME(this));
168 tray_accessibility_ = new internal::TrayAccessibility(this);
169 AddTrayItem(tray_accessibility_);
170 #if defined(OS_CHROMEOS)
171 AddTrayItem(new internal::TrayTracing(this));
172 AddTrayItem(
173 new internal::TrayPower(this, message_center::MessageCenter::Get()));
174 #endif
175 #if defined(OS_CHROMEOS)
176 AddTrayItem(new internal::TrayNetwork(this));
177 AddTrayItem(new internal::TrayVPN(this));
178 AddTrayItem(new internal::TraySms(this));
179 #endif
180 #if !defined(OS_WIN)
181 AddTrayItem(new internal::TrayBluetooth(this));
182 #endif
183 AddTrayItem(new internal::TrayDrive(this));
184 #if defined(OS_CHROMEOS)
185 AddTrayItem(new internal::TrayDisplay(this));
186 AddTrayItem(new internal::ScreenCaptureTrayItem(this));
187 AddTrayItem(new internal::ScreenShareTrayItem(this));
188 AddTrayItem(new internal::TrayAudio(this));
189 #endif
190 #if !defined(OS_WIN)
191 AddTrayItem(new internal::TrayBrightness(this));
192 AddTrayItem(new internal::TrayCapsLock(this));
193 #endif
194 #if defined(OS_CHROMEOS)
195 AddTrayItem(new internal::TraySettings(this));
196 #endif
197 AddTrayItem(new internal::TrayUpdate(this));
198 AddTrayItem(new internal::TrayDate(this));
200 #if defined(OS_LINUX)
201 // Add memory monitor if enabled.
202 CommandLine* cmd = CommandLine::ForCurrentProcess();
203 if (cmd->HasSwitch(ash::switches::kAshEnableMemoryMonitor))
204 AddTrayItem(new internal::TrayMonitor(this));
205 #endif
207 SetVisible(ash::Shell::GetInstance()->system_tray_delegate()->
208 GetTrayVisibilityOnStartup());
211 void SystemTray::AddTrayItem(SystemTrayItem* item) {
212 items_.push_back(item);
214 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
215 views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus());
216 item->UpdateAfterShelfAlignmentChange(shelf_alignment());
218 if (tray_item) {
219 tray_container()->AddChildViewAt(tray_item, 0);
220 PreferredSizeChanged();
221 tray_item_map_[item] = tray_item;
225 void SystemTray::RemoveTrayItem(SystemTrayItem* item) {
226 NOTIMPLEMENTED();
229 const std::vector<SystemTrayItem*>& SystemTray::GetTrayItems() const {
230 return items_.get();
233 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) {
234 ShowDefaultViewWithOffset(creation_type,
235 TrayBubbleView::InitParams::kArrowDefaultOffset);
238 void SystemTray::ShowDetailedView(SystemTrayItem* item,
239 int close_delay,
240 bool activate,
241 BubbleCreationType creation_type) {
242 std::vector<SystemTrayItem*> items;
243 items.push_back(item);
244 ShowItems(items, true, activate, creation_type, GetTrayXOffset(item));
245 if (system_bubble_)
246 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
249 void SystemTray::SetDetailedViewCloseDelay(int close_delay) {
250 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED))
251 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
254 void SystemTray::HideDetailedView(SystemTrayItem* item) {
255 if (item != detailed_item_)
256 return;
257 DestroySystemBubble();
258 UpdateNotificationBubble();
261 void SystemTray::ShowNotificationView(SystemTrayItem* item) {
262 if (std::find(notification_items_.begin(), notification_items_.end(), item)
263 != notification_items_.end())
264 return;
265 notification_items_.push_back(item);
266 UpdateNotificationBubble();
269 void SystemTray::HideNotificationView(SystemTrayItem* item) {
270 std::vector<SystemTrayItem*>::iterator found_iter =
271 std::find(notification_items_.begin(), notification_items_.end(), item);
272 if (found_iter == notification_items_.end())
273 return;
274 notification_items_.erase(found_iter);
275 // Only update the notification bubble if visible (i.e. don't create one).
276 if (notification_bubble_)
277 UpdateNotificationBubble();
280 void SystemTray::UpdateAfterLoginStatusChange(user::LoginStatus login_status) {
281 DestroySystemBubble();
282 UpdateNotificationBubble();
284 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
285 it != items_.end();
286 ++it) {
287 (*it)->UpdateAfterLoginStatusChange(login_status);
290 // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial
291 // position of the shelf differs.
292 if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM)
293 UpdateAfterShelfAlignmentChange(shelf_alignment());
295 SetVisible(true);
296 PreferredSizeChanged();
299 void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
300 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
301 it != items_.end();
302 ++it) {
303 (*it)->UpdateAfterShelfAlignmentChange(alignment);
307 void SystemTray::SetHideNotifications(bool hide_notifications) {
308 if (notification_bubble_)
309 notification_bubble_->bubble()->SetVisible(!hide_notifications);
310 hide_notifications_ = hide_notifications;
313 bool SystemTray::ShouldShowLauncher() const {
314 return system_bubble_.get() && system_bubble_->bubble()->ShouldShowLauncher();
317 bool SystemTray::HasSystemBubble() const {
318 return system_bubble_.get() != NULL;
321 bool SystemTray::HasNotificationBubble() const {
322 return notification_bubble_.get() != NULL;
325 bool SystemTray::IsPressed() {
326 // Only when a full system tray bubble gets shown true will be returned.
327 // Small bubbles (like audio modifications via keyboard) should return false.
328 // Since showing the e.g. network portion of the system tray menu will convert
329 // the |system_bubble_| from type |BUBBLE_TYPE_DEFAULT| into
330 // |BUBBLE_TYPE_DETAILED| the full tray cannot reliably be checked trhough the
331 // type. As such |full_system_tray_menu_| gets checked here.
332 return HasSystemBubble() && full_system_tray_menu_;
335 internal::SystemTrayBubble* SystemTray::GetSystemBubble() {
336 if (!system_bubble_)
337 return NULL;
338 return system_bubble_->bubble();
341 bool SystemTray::IsAnyBubbleVisible() const {
342 return ((system_bubble_.get() &&
343 system_bubble_->bubble()->IsVisible()) ||
344 (notification_bubble_.get() &&
345 notification_bubble_->bubble()->IsVisible()));
348 bool SystemTray::IsMouseInNotificationBubble() const {
349 if (!notification_bubble_)
350 return false;
351 return notification_bubble_->bubble_view()->GetBoundsInScreen().Contains(
352 Shell::GetScreen()->GetCursorScreenPoint());
355 bool SystemTray::CloseSystemBubble() const {
356 if (!system_bubble_)
357 return false;
358 system_bubble_->bubble()->Close();
359 return true;
362 bool SystemTray::CloseNotificationBubbleForTest() const {
363 if (!notification_bubble_)
364 return false;
365 notification_bubble_->bubble()->Close();
366 return true;
369 // Private methods.
371 bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) {
372 DCHECK(type != SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
373 return system_bubble_.get() && system_bubble_->bubble_type() == type;
376 void SystemTray::DestroySystemBubble() {
377 system_bubble_.reset();
378 detailed_item_ = NULL;
379 UpdateWebNotifications();
382 void SystemTray::DestroyNotificationBubble() {
383 if (notification_bubble_) {
384 notification_bubble_.reset();
385 UpdateWebNotifications();
389 int SystemTray::GetTrayXOffset(SystemTrayItem* item) const {
390 // Don't attempt to align the arrow if the shelf is on the left or right.
391 if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM &&
392 shelf_alignment() != SHELF_ALIGNMENT_TOP)
393 return TrayBubbleView::InitParams::kArrowDefaultOffset;
395 std::map<SystemTrayItem*, views::View*>::const_iterator it =
396 tray_item_map_.find(item);
397 if (it == tray_item_map_.end())
398 return TrayBubbleView::InitParams::kArrowDefaultOffset;
400 const views::View* item_view = it->second;
401 if (item_view->bounds().IsEmpty()) {
402 // The bounds of item could be still empty if it does not have a visible
403 // tray view. In that case, use the default (minimum) offset.
404 return TrayBubbleView::InitParams::kArrowDefaultOffset;
407 gfx::Point point(item_view->width() / 2, 0);
408 ConvertPointToWidget(item_view, &point);
409 return point.x();
412 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type,
413 int arrow_offset) {
414 ShowItems(items_.get(), false, true, creation_type, arrow_offset);
417 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
418 bool detailed,
419 bool can_activate,
420 BubbleCreationType creation_type,
421 int arrow_offset) {
422 // No system tray bubbles in kiosk mode.
423 if (Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus() ==
424 ash::user::LOGGED_IN_KIOSK_APP) {
425 return;
428 // Destroy any existing bubble and create a new one.
429 SystemTrayBubble::BubbleType bubble_type = detailed ?
430 SystemTrayBubble::BUBBLE_TYPE_DETAILED :
431 SystemTrayBubble::BUBBLE_TYPE_DEFAULT;
433 // Destroy the notification bubble here so that it doesn't get rebuilt
434 // while we add items to the main bubble_ (e.g. in HideNotificationView).
435 notification_bubble_.reset();
436 if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) {
437 system_bubble_->bubble()->UpdateView(items, bubble_type);
438 } else {
439 // Remember if the menu is a single property (like e.g. volume) or the
440 // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case
441 // above, |full_system_tray_menu_| does not get changed since the fact that
442 // the menu is full (or not) doesn't change even if a "single property"
443 // (like network) replaces most of the menu.
444 full_system_tray_menu_ = items.size() > 1;
445 // The menu width is fixed, and it is a per language setting.
446 int menu_width = std::max(kMinimumSystemTrayMenuWidth,
447 Shell::GetInstance()->system_tray_delegate()->GetSystemTrayMenuWidth());
449 TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
450 GetAnchorAlignment(),
451 menu_width,
452 kTrayPopupMaxWidth);
453 init_params.can_activate = can_activate;
454 init_params.first_item_has_no_margin =
455 ash::switches::UseAlternateShelfLayout();
456 if (detailed) {
457 // This is the case where a volume control or brightness control bubble
458 // is created.
459 init_params.max_height = default_bubble_height_;
460 init_params.arrow_color = kBackgroundColor;
461 } else {
462 init_params.arrow_color = kHeaderBackgroundColor;
464 init_params.arrow_offset = arrow_offset;
465 // For Volume and Brightness we don't want to show an arrow when
466 // they are shown in a bubble by themselves.
467 init_params.arrow_paint_type = views::BubbleBorder::PAINT_NORMAL;
468 if (items.size() == 1 && items[0]->ShouldHideArrow())
469 init_params.arrow_paint_type = views::BubbleBorder::PAINT_TRANSPARENT;
470 SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type);
471 system_bubble_.reset(new internal::SystemBubbleWrapper(bubble));
472 system_bubble_->InitView(this, tray_container(), &init_params);
474 // Save height of default view for creating detailed views directly.
475 if (!detailed)
476 default_bubble_height_ = system_bubble_->bubble_view()->height();
478 if (detailed && items.size() > 0)
479 detailed_item_ = items[0];
480 else
481 detailed_item_ = NULL;
483 UpdateNotificationBubble(); // State changed, re-create notifications.
484 if (!notification_bubble_)
485 UpdateWebNotifications();
486 GetShelfLayoutManager()->UpdateAutoHideState();
489 void SystemTray::UpdateNotificationBubble() {
490 // Only show the notification bubble if we have notifications.
491 if (notification_items_.empty()) {
492 DestroyNotificationBubble();
493 return;
495 // Destroy the existing bubble before constructing a new one.
496 notification_bubble_.reset();
497 SystemTrayBubble* notification_bubble;
498 notification_bubble = new SystemTrayBubble(
499 this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
500 views::View* anchor;
501 TrayBubbleView::AnchorType anchor_type;
502 // Tray items might want to show notifications while we are creating and
503 // initializing the |system_bubble_| - but it might not be fully initialized
504 // when coming here - this would produce a crashed like crbug.com/247416.
505 // As such we check the existence of the widget here.
506 if (system_bubble_.get() &&
507 system_bubble_->bubble_view() &&
508 system_bubble_->bubble_view()->GetWidget()) {
509 anchor = system_bubble_->bubble_view();
510 anchor_type = TrayBubbleView::ANCHOR_TYPE_BUBBLE;
511 } else {
512 anchor = tray_container();
513 anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY;
515 TrayBubbleView::InitParams init_params(anchor_type,
516 GetAnchorAlignment(),
517 kTrayPopupMinWidth,
518 kTrayPopupMaxWidth);
519 init_params.first_item_has_no_margin =
520 ash::switches::UseAlternateShelfLayout();
521 init_params.arrow_color = kBackgroundColor;
522 init_params.arrow_offset = GetTrayXOffset(notification_items_[0]);
523 notification_bubble_.reset(
524 new internal::SystemBubbleWrapper(notification_bubble));
525 notification_bubble_->InitView(this, anchor, &init_params);
527 if (notification_bubble->bubble_view()->child_count() == 0) {
528 // It is possible that none of the items generated actual notifications.
529 DestroyNotificationBubble();
530 return;
532 if (hide_notifications_)
533 notification_bubble->SetVisible(false);
534 else
535 UpdateWebNotifications();
538 void SystemTray::UpdateWebNotifications() {
539 TrayBubbleView* bubble_view = NULL;
540 if (notification_bubble_)
541 bubble_view = notification_bubble_->bubble_view();
542 else if (system_bubble_)
543 bubble_view = system_bubble_->bubble_view();
545 int height = 0;
546 if (bubble_view) {
547 gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
548 bubble_view->GetWidget()->GetNativeView()).work_area();
549 if (GetShelfLayoutManager()->GetAlignment() != SHELF_ALIGNMENT_TOP) {
550 height = std::max(
551 0, work_area.height() - bubble_view->GetBoundsInScreen().y());
552 } else {
553 height = std::max(
554 0, bubble_view->GetBoundsInScreen().bottom() - work_area.y());
557 status_area_widget()->web_notification_tray()->SetSystemTrayHeight(height);
560 void SystemTray::SetShelfAlignment(ShelfAlignment alignment) {
561 if (alignment == shelf_alignment())
562 return;
563 internal::TrayBackgroundView::SetShelfAlignment(alignment);
564 UpdateAfterShelfAlignmentChange(alignment);
565 // Destroy any existing bubble so that it is rebuilt correctly.
566 system_bubble_.reset();
567 // Rebuild any notification bubble.
568 if (notification_bubble_) {
569 notification_bubble_.reset();
570 UpdateNotificationBubble();
574 void SystemTray::AnchorUpdated() {
575 if (notification_bubble_) {
576 notification_bubble_->bubble_view()->UpdateBubble();
577 // Ensure that the notification buble is above the launcher/status area.
578 notification_bubble_->bubble_view()->GetWidget()->StackAtTop();
579 UpdateBubbleViewArrow(notification_bubble_->bubble_view());
581 if (system_bubble_) {
582 system_bubble_->bubble_view()->UpdateBubble();
583 UpdateBubbleViewArrow(system_bubble_->bubble_view());
587 base::string16 SystemTray::GetAccessibleNameForTray() {
588 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
591 void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
592 if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) {
593 DestroySystemBubble();
594 UpdateNotificationBubble(); // State changed, re-create notifications.
595 GetShelfLayoutManager()->UpdateAutoHideState();
596 } else if (notification_bubble_.get() &&
597 bubble_view == notification_bubble_->bubble_view()) {
598 DestroyNotificationBubble();
602 bool SystemTray::ClickedOutsideBubble() {
603 if (!system_bubble_)
604 return false;
605 HideBubbleWithView(system_bubble_->bubble_view());
606 return true;
609 void SystemTray::BubbleViewDestroyed() {
610 if (system_bubble_) {
611 system_bubble_->bubble()->DestroyItemViews();
612 system_bubble_->bubble()->BubbleViewDestroyed();
616 void SystemTray::OnMouseEnteredView() {
617 if (system_bubble_)
618 system_bubble_->bubble()->StopAutoCloseTimer();
621 void SystemTray::OnMouseExitedView() {
622 if (system_bubble_)
623 system_bubble_->bubble()->RestartAutoCloseTimer();
626 base::string16 SystemTray::GetAccessibleNameForBubble() {
627 return GetAccessibleNameForTray();
630 gfx::Rect SystemTray::GetAnchorRect(
631 views::Widget* anchor_widget,
632 TrayBubbleView::AnchorType anchor_type,
633 TrayBubbleView::AnchorAlignment anchor_alignment) {
634 return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment);
637 void SystemTray::HideBubble(const TrayBubbleView* bubble_view) {
638 HideBubbleWithView(bubble_view);
641 bool SystemTray::PerformAction(const ui::Event& event) {
642 // If we're already showing the default view, hide it; otherwise, show it
643 // (and hide any popup that's currently shown).
644 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) {
645 system_bubble_->bubble()->Close();
646 } else {
647 int arrow_offset = TrayBubbleView::InitParams::kArrowDefaultOffset;
648 if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) {
649 const ui::LocatedEvent& located_event =
650 static_cast<const ui::LocatedEvent&>(event);
651 if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM ||
652 shelf_alignment() == SHELF_ALIGNMENT_TOP) {
653 gfx::Point point(located_event.x(), 0);
654 ConvertPointToWidget(this, &point);
655 arrow_offset = point.x();
658 ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset);
660 return true;
663 } // namespace ash