Add toplevel trace event to MessagePumpLibevent::OnLibeventNotification
[chromium-blink-merge.git] / ash / system / tray / system_tray_unittest.cc
blobc61776ef62679345686e42f1e43ce401875cc47c
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 <vector>
9 #include "ash/accessibility_delegate.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/shelf/shelf_layout_manager.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/system/status_area_widget.h"
15 #include "ash/system/tray/system_tray_bubble.h"
16 #include "ash/system/tray/system_tray_item.h"
17 #include "ash/system/tray/tray_constants.h"
18 #include "ash/system/tray/tray_popup_item_container.h"
19 #include "ash/test/ash_test_base.h"
20 #include "ash/wm/window_util.h"
21 #include "base/run_loop.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "ui/aura/window.h"
24 #include "ui/base/ui_base_types.h"
25 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
26 #include "ui/events/test/event_generator.h"
27 #include "ui/gfx/geometry/point.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/views/controls/label.h"
30 #include "ui/views/layout/fill_layout.h"
31 #include "ui/views/view.h"
32 #include "ui/views/widget/widget.h"
33 #include "ui/views/widget/widget_delegate.h"
35 #if defined(OS_WIN)
36 #include "base/win/windows_version.h"
37 #endif
39 namespace ash {
40 namespace test {
42 namespace {
44 SystemTray* GetSystemTray() {
45 return Shell::GetPrimaryRootWindowController()->shelf()->
46 status_area_widget()->system_tray();
49 // Trivial item implementation that tracks its views for testing.
50 class TestItem : public SystemTrayItem {
51 public:
52 TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL) {}
54 views::View* CreateTrayView(user::LoginStatus status) override {
55 tray_view_ = new views::View;
56 // Add a label so it has non-zero width.
57 tray_view_->SetLayoutManager(new views::FillLayout);
58 tray_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Tray")));
59 return tray_view_;
62 views::View* CreateDefaultView(user::LoginStatus status) override {
63 default_view_ = new views::View;
64 default_view_->SetLayoutManager(new views::FillLayout);
65 default_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Default")));
66 return default_view_;
69 views::View* CreateDetailedView(user::LoginStatus status) override {
70 detailed_view_ = new views::View;
71 detailed_view_->SetLayoutManager(new views::FillLayout);
72 detailed_view_->AddChildView(
73 new views::Label(base::UTF8ToUTF16("Detailed")));
74 return detailed_view_;
77 views::View* CreateNotificationView(user::LoginStatus status) override {
78 notification_view_ = new views::View;
79 return notification_view_;
82 void DestroyTrayView() override { tray_view_ = NULL; }
84 void DestroyDefaultView() override { default_view_ = NULL; }
86 void DestroyDetailedView() override { detailed_view_ = NULL; }
88 void DestroyNotificationView() override { notification_view_ = NULL; }
90 void UpdateAfterLoginStatusChange(user::LoginStatus status) override {}
92 views::View* tray_view() const { return tray_view_; }
93 views::View* default_view() const { return default_view_; }
94 views::View* detailed_view() const { return detailed_view_; }
95 views::View* notification_view() const { return notification_view_; }
97 private:
98 views::View* tray_view_;
99 views::View* default_view_;
100 views::View* detailed_view_;
101 views::View* notification_view_;
104 // Trivial item implementation that returns NULL from tray/default/detailed
105 // view creation methods.
106 class TestNoViewItem : public SystemTrayItem {
107 public:
108 TestNoViewItem() : SystemTrayItem(GetSystemTray()) {}
110 views::View* CreateTrayView(user::LoginStatus status) override {
111 return NULL;
114 views::View* CreateDefaultView(user::LoginStatus status) override {
115 return NULL;
118 views::View* CreateDetailedView(user::LoginStatus status) override {
119 return NULL;
122 views::View* CreateNotificationView(user::LoginStatus status) override {
123 return NULL;
126 void DestroyTrayView() override {}
127 void DestroyDefaultView() override {}
128 void DestroyDetailedView() override {}
129 void DestroyNotificationView() override {}
130 void UpdateAfterLoginStatusChange(user::LoginStatus status) override {}
133 class ModalWidgetDelegate : public views::WidgetDelegateView {
134 public:
135 ModalWidgetDelegate() {}
136 ~ModalWidgetDelegate() override {}
138 views::View* GetContentsView() override { return this; }
139 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_SYSTEM; }
141 private:
142 DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
145 } // namespace
147 typedef AshTestBase SystemTrayTest;
149 TEST_F(SystemTrayTest, SystemTrayDefaultView) {
150 SystemTray* tray = GetSystemTray();
151 ASSERT_TRUE(tray->GetWidget());
153 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
155 // Ensure that closing the bubble destroys it.
156 ASSERT_TRUE(tray->CloseSystemBubble());
157 RunAllPendingInMessageLoop();
158 ASSERT_FALSE(tray->CloseSystemBubble());
161 // Opening and closing the bubble should change the coloring of the tray.
162 TEST_F(SystemTrayTest, SystemTrayColoring) {
163 SystemTray* tray = GetSystemTray();
164 ASSERT_TRUE(tray->GetWidget());
165 // At the beginning the tray coloring is not active.
166 ASSERT_FALSE(tray->draw_background_as_active());
168 // Showing the system bubble should show the background as active.
169 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
170 ASSERT_TRUE(tray->draw_background_as_active());
172 // Closing the system menu should change the coloring back to normal.
173 ASSERT_TRUE(tray->CloseSystemBubble());
174 RunAllPendingInMessageLoop();
175 ASSERT_FALSE(tray->draw_background_as_active());
178 // Closing the system bubble through an alignment change should change the
179 // system tray coloring back to normal.
180 TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) {
181 SystemTray* tray = GetSystemTray();
182 ASSERT_TRUE(tray->GetWidget());
183 ShelfLayoutManager* manager =
184 Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
185 manager->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
186 // At the beginning the tray coloring is not active.
187 ASSERT_FALSE(tray->draw_background_as_active());
189 // Showing the system bubble should show the background as active.
190 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
191 ASSERT_TRUE(tray->draw_background_as_active());
193 // Changing the alignment should close the system bubble and change the
194 // background color.
195 manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
196 ASSERT_FALSE(tray->draw_background_as_active());
197 RunAllPendingInMessageLoop();
198 // The bubble should already be closed by now.
199 ASSERT_FALSE(tray->CloseSystemBubble());
202 TEST_F(SystemTrayTest, SystemTrayTestItems) {
203 SystemTray* tray = GetSystemTray();
204 ASSERT_TRUE(tray->GetWidget());
206 TestItem* test_item = new TestItem;
207 TestItem* detailed_item = new TestItem;
208 tray->AddTrayItem(test_item);
209 tray->AddTrayItem(detailed_item);
211 // Check items have been added
212 const std::vector<SystemTrayItem*>& items = tray->GetTrayItems();
213 ASSERT_TRUE(
214 std::find(items.begin(), items.end(), test_item) != items.end());
215 ASSERT_TRUE(
216 std::find(items.begin(), items.end(), detailed_item) != items.end());
218 // Ensure the tray views are created.
219 ASSERT_TRUE(test_item->tray_view() != NULL);
220 ASSERT_TRUE(detailed_item->tray_view() != NULL);
222 // Ensure a default views are created.
223 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
224 ASSERT_TRUE(test_item->default_view() != NULL);
225 ASSERT_TRUE(detailed_item->default_view() != NULL);
227 // Show the detailed view, ensure it's created and the default view destroyed.
228 tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
229 RunAllPendingInMessageLoop();
230 ASSERT_TRUE(test_item->default_view() == NULL);
231 ASSERT_TRUE(detailed_item->detailed_view() != NULL);
233 // Show the default view, ensure it's created and the detailed view destroyed.
234 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
235 RunAllPendingInMessageLoop();
236 ASSERT_TRUE(test_item->default_view() != NULL);
237 ASSERT_TRUE(detailed_item->detailed_view() == NULL);
240 TEST_F(SystemTrayTest, SystemTrayNoViewItems) {
241 SystemTray* tray = GetSystemTray();
242 ASSERT_TRUE(tray->GetWidget());
244 // Verify that no crashes occur on items lacking some views.
245 TestNoViewItem* no_view_item = new TestNoViewItem;
246 tray->AddTrayItem(no_view_item);
247 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
248 tray->ShowDetailedView(no_view_item, 0, false, BUBBLE_USE_EXISTING);
249 RunAllPendingInMessageLoop();
252 TEST_F(SystemTrayTest, TrayWidgetAutoResizes) {
253 SystemTray* tray = GetSystemTray();
254 ASSERT_TRUE(tray->GetWidget());
256 // Add an initial tray item so that the tray gets laid out correctly.
257 TestItem* initial_item = new TestItem;
258 tray->AddTrayItem(initial_item);
260 gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
262 TestItem* new_item = new TestItem;
263 tray->AddTrayItem(new_item);
265 gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
267 // Adding the new item should change the size of the tray.
268 EXPECT_NE(initial_size.ToString(), new_size.ToString());
270 // Hiding the tray view of the new item should also change the size of the
271 // tray.
272 new_item->tray_view()->SetVisible(false);
273 EXPECT_EQ(initial_size.ToString(),
274 tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
276 new_item->tray_view()->SetVisible(true);
277 EXPECT_EQ(new_size.ToString(),
278 tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
281 TEST_F(SystemTrayTest, SystemTrayNotifications) {
282 SystemTray* tray = GetSystemTray();
283 ASSERT_TRUE(tray->GetWidget());
285 TestItem* test_item = new TestItem;
286 TestItem* detailed_item = new TestItem;
287 tray->AddTrayItem(test_item);
288 tray->AddTrayItem(detailed_item);
290 // Ensure the tray views are created.
291 ASSERT_TRUE(test_item->tray_view() != NULL);
292 ASSERT_TRUE(detailed_item->tray_view() != NULL);
294 // Ensure a notification view is created.
295 tray->ShowNotificationView(test_item);
296 ASSERT_TRUE(test_item->notification_view() != NULL);
298 // Show the default view, notification view should remain.
299 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
300 RunAllPendingInMessageLoop();
301 ASSERT_TRUE(test_item->notification_view() != NULL);
303 // Show the detailed view, ensure the notification view remains.
304 tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
305 RunAllPendingInMessageLoop();
306 ASSERT_TRUE(detailed_item->detailed_view() != NULL);
307 ASSERT_TRUE(test_item->notification_view() != NULL);
309 // Hide the detailed view, ensure the notification view still exists.
310 ASSERT_TRUE(tray->CloseSystemBubble());
311 RunAllPendingInMessageLoop();
312 ASSERT_TRUE(detailed_item->detailed_view() == NULL);
313 ASSERT_TRUE(test_item->notification_view() != NULL);
316 TEST_F(SystemTrayTest, BubbleCreationTypesTest) {
317 SystemTray* tray = GetSystemTray();
318 ASSERT_TRUE(tray->GetWidget());
320 TestItem* test_item = new TestItem;
321 tray->AddTrayItem(test_item);
323 // Ensure the tray views are created.
324 ASSERT_TRUE(test_item->tray_view() != NULL);
326 // Show the default view, ensure the notification view is destroyed.
327 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
328 RunAllPendingInMessageLoop();
330 views::Widget* widget = test_item->default_view()->GetWidget();
331 gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen();
333 tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING);
334 RunAllPendingInMessageLoop();
336 EXPECT_FALSE(test_item->default_view());
338 EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view()->GetWidget()->
339 GetWindowBoundsInScreen().ToString());
340 EXPECT_EQ(widget, test_item->detailed_view()->GetWidget());
342 tray->ShowDefaultView(BUBBLE_USE_EXISTING);
343 RunAllPendingInMessageLoop();
345 EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view()->GetWidget()->
346 GetWindowBoundsInScreen().ToString());
347 EXPECT_EQ(widget, test_item->default_view()->GetWidget());
350 // Tests that the tray is laid out properly and is fully contained within
351 // the shelf.
352 TEST_F(SystemTrayTest, TrayBoundsInWidget) {
353 ShelfLayoutManager* manager =
354 Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
355 StatusAreaWidget* widget =
356 Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
357 SystemTray* tray = widget->system_tray();
359 // Test in bottom alignment.
360 manager->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
361 gfx::Rect window_bounds = widget->GetWindowBoundsInScreen();
362 gfx::Rect tray_bounds = tray->GetBoundsInScreen();
363 EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
364 EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
365 EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
366 EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
368 // Test in the left alignment.
369 manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
370 window_bounds = widget->GetWindowBoundsInScreen();
371 tray_bounds = tray->GetBoundsInScreen();
372 EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
373 EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
374 EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
375 EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
377 // Test in the right alignment.
378 manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
379 window_bounds = widget->GetWindowBoundsInScreen();
380 tray_bounds = tray->GetBoundsInScreen();
381 EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
382 EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
383 EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
384 EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
387 TEST_F(SystemTrayTest, PersistentBubble) {
388 SystemTray* tray = GetSystemTray();
389 ASSERT_TRUE(tray->GetWidget());
391 TestItem* test_item = new TestItem;
392 tray->AddTrayItem(test_item);
394 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
396 // Tests for usual default view.
397 // Activating window.
398 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
399 ASSERT_TRUE(tray->HasSystemBubble());
400 wm::ActivateWindow(window.get());
401 base::RunLoop().RunUntilIdle();
402 ASSERT_FALSE(tray->HasSystemBubble());
404 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
405 ASSERT_TRUE(tray->HasSystemBubble());
407 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
408 gfx::Point(5, 5));
409 generator.ClickLeftButton();
410 ASSERT_FALSE(tray->HasSystemBubble());
413 // Same tests for persistent default view.
414 tray->ShowPersistentDefaultView();
415 ASSERT_TRUE(tray->HasSystemBubble());
416 wm::ActivateWindow(window.get());
417 base::RunLoop().RunUntilIdle();
418 ASSERT_TRUE(tray->HasSystemBubble());
421 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
422 gfx::Point(5, 5));
423 generator.ClickLeftButton();
424 ASSERT_TRUE(tray->HasSystemBubble());
428 #if defined(OS_CHROMEOS)
429 // Accessibility/Settings tray items are available only on cros.
430 #define MAYBE_WithSystemModal WithSystemModal
431 #else
432 #define MAYBE_WithSystemModal DISABLED_WithSystemModal
433 #endif
434 TEST_F(SystemTrayTest, MAYBE_WithSystemModal) {
435 // Check if the accessibility item is created even with system modal
436 // dialog.
437 Shell::GetInstance()->accessibility_delegate()->SetVirtualKeyboardEnabled(
438 true);
439 views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
440 new ModalWidgetDelegate(),
441 Shell::GetPrimaryRootWindow(),
442 gfx::Rect(0, 0, 100, 100));
443 widget->Show();
445 SystemTray* tray = GetSystemTray();
446 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
448 ASSERT_TRUE(tray->HasSystemBubble());
449 const views::View* accessibility =
450 tray->GetSystemBubble()->bubble_view()->GetViewByID(
451 test::kAccessibilityTrayItemViewId);
452 ASSERT_TRUE(accessibility);
453 EXPECT_TRUE(accessibility->visible());
454 EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetViewByID(
455 test::kSettingsTrayItemViewId));
457 widget->Close();
459 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
460 // System modal is gone. The bubble should now contains settings
461 // as well.
462 accessibility = tray->GetSystemBubble()->bubble_view()->GetViewByID(
463 test::kAccessibilityTrayItemViewId);
464 ASSERT_TRUE(accessibility);
465 EXPECT_TRUE(accessibility->visible());
467 const views::View* settings =
468 tray->GetSystemBubble()->bubble_view()->GetViewByID(
469 test::kSettingsTrayItemViewId);
470 ASSERT_TRUE(settings);
471 EXPECT_TRUE(settings->visible());
474 // Tests that if SetVisible(true) is called while animating to hidden that the
475 // tray becomes visible, and stops animating to hidden.
476 TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) {
477 SystemTray* tray = GetSystemTray();
478 ASSERT_TRUE(tray->visible());
480 scoped_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration;
481 animation_duration.reset(
482 new ui::ScopedAnimationDurationScaleMode(
483 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
484 tray->SetVisible(false);
485 EXPECT_TRUE(tray->visible());
486 EXPECT_EQ(0.0f, tray->layer()->GetTargetOpacity());
488 tray->SetVisible(true);
489 animation_duration.reset();
490 tray->layer()->GetAnimator()->StopAnimating();
491 EXPECT_TRUE(tray->visible());
492 EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity());
495 #if defined(OS_CHROMEOS)
496 // Tests that touch on an item in the system bubble triggers it to become
497 // active.
498 TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedback) {
499 SystemTray* tray = GetSystemTray();
500 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
502 TrayPopupItemContainer* view =
503 static_cast<TrayPopupItemContainer*>(tray->GetSystemBubble()->
504 bubble_view()->child_at(0));
505 EXPECT_FALSE(view->active());
507 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
508 generator.set_current_location(view->GetBoundsInScreen().CenterPoint());
509 generator.PressTouch();
510 EXPECT_TRUE(view->active());
512 generator.ReleaseTouch();
513 EXPECT_FALSE(view->active());
516 // Tests that touch events on an item in the system bubble cause it to stop
517 // being active.
518 TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedbackCancellation) {
519 SystemTray* tray = GetSystemTray();
520 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
522 TrayPopupItemContainer* view =
523 static_cast<TrayPopupItemContainer*>(tray->GetSystemBubble()->
524 bubble_view()->child_at(0));
525 EXPECT_FALSE(view->active());
527 gfx::Rect view_bounds = view->GetBoundsInScreen();
528 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
529 generator.set_current_location(view_bounds.CenterPoint());
530 generator.PressTouch();
531 EXPECT_TRUE(view->active());
533 gfx::Point move_point(view_bounds.x(), view_bounds.CenterPoint().y());
534 generator.MoveTouch(move_point);
535 EXPECT_FALSE(view->active());
537 generator.set_current_location(move_point);
538 generator.ReleaseTouch();
539 EXPECT_FALSE(view->active());
541 #endif // OS_CHROMEOS
543 } // namespace test
544 } // namespace ash