Added unit test for DevTools' ephemeral port support.
[chromium-blink-merge.git] / ash / system / tray / system_tray_unittest.cc
blobc798e78c09823134e2e0b8b8026a794e474ba2ac
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_item.h"
16 #include "ash/system/tray/tray_constants.h"
17 #include "ash/test/ash_test_base.h"
18 #include "ash/wm/window_util.h"
19 #include "base/run_loop.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "ui/aura/test/event_generator.h"
22 #include "ui/aura/window.h"
23 #include "ui/base/ui_base_types.h"
24 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
25 #include "ui/gfx/geometry/rect.h"
26 #include "ui/views/controls/label.h"
27 #include "ui/views/layout/fill_layout.h"
28 #include "ui/views/view.h"
29 #include "ui/views/widget/widget.h"
30 #include "ui/views/widget/widget_delegate.h"
32 #if defined(OS_WIN)
33 #include "base/win/windows_version.h"
34 #endif
36 namespace ash {
37 namespace test {
39 namespace {
41 SystemTray* GetSystemTray() {
42 return Shell::GetPrimaryRootWindowController()->shelf()->
43 status_area_widget()->system_tray();
46 // Trivial item implementation that tracks its views for testing.
47 class TestItem : public SystemTrayItem {
48 public:
49 TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL) {}
51 virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE {
52 tray_view_ = new views::View;
53 // Add a label so it has non-zero width.
54 tray_view_->SetLayoutManager(new views::FillLayout);
55 tray_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Tray")));
56 return tray_view_;
59 virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
60 default_view_ = new views::View;
61 default_view_->SetLayoutManager(new views::FillLayout);
62 default_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Default")));
63 return default_view_;
66 virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE {
67 detailed_view_ = new views::View;
68 detailed_view_->SetLayoutManager(new views::FillLayout);
69 detailed_view_->AddChildView(
70 new views::Label(base::UTF8ToUTF16("Detailed")));
71 return detailed_view_;
74 virtual views::View* CreateNotificationView(
75 user::LoginStatus status) OVERRIDE {
76 notification_view_ = new views::View;
77 return notification_view_;
80 virtual void DestroyTrayView() OVERRIDE {
81 tray_view_ = NULL;
84 virtual void DestroyDefaultView() OVERRIDE {
85 default_view_ = NULL;
88 virtual void DestroyDetailedView() OVERRIDE {
89 detailed_view_ = NULL;
92 virtual void DestroyNotificationView() OVERRIDE {
93 notification_view_ = NULL;
96 virtual void UpdateAfterLoginStatusChange(
97 user::LoginStatus status) OVERRIDE {
100 views::View* tray_view() const { return tray_view_; }
101 views::View* default_view() const { return default_view_; }
102 views::View* detailed_view() const { return detailed_view_; }
103 views::View* notification_view() const { return notification_view_; }
105 private:
106 views::View* tray_view_;
107 views::View* default_view_;
108 views::View* detailed_view_;
109 views::View* notification_view_;
112 // Trivial item implementation that returns NULL from tray/default/detailed
113 // view creation methods.
114 class TestNoViewItem : public SystemTrayItem {
115 public:
116 TestNoViewItem() : SystemTrayItem(GetSystemTray()) {}
118 virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE {
119 return NULL;
122 virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
123 return NULL;
126 virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE {
127 return NULL;
130 virtual views::View* CreateNotificationView(
131 user::LoginStatus status) OVERRIDE {
132 return NULL;
135 virtual void DestroyTrayView() OVERRIDE {}
136 virtual void DestroyDefaultView() OVERRIDE {}
137 virtual void DestroyDetailedView() OVERRIDE {}
138 virtual void DestroyNotificationView() OVERRIDE {}
139 virtual void UpdateAfterLoginStatusChange(
140 user::LoginStatus status) OVERRIDE {
144 class ModalWidgetDelegate : public views::WidgetDelegateView {
145 public:
146 ModalWidgetDelegate() {}
147 virtual ~ModalWidgetDelegate() {}
149 virtual views::View* GetContentsView() OVERRIDE { return this; }
150 virtual ui::ModalType GetModalType() const OVERRIDE {
151 return ui::MODAL_TYPE_SYSTEM;
154 private:
155 DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
158 } // namespace
160 typedef AshTestBase SystemTrayTest;
162 TEST_F(SystemTrayTest, SystemTrayDefaultView) {
163 SystemTray* tray = GetSystemTray();
164 ASSERT_TRUE(tray->GetWidget());
166 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
168 // Ensure that closing the bubble destroys it.
169 ASSERT_TRUE(tray->CloseSystemBubble());
170 RunAllPendingInMessageLoop();
171 ASSERT_FALSE(tray->CloseSystemBubble());
174 // Opening and closing the bubble should change the coloring of the tray.
175 TEST_F(SystemTrayTest, SystemTrayColoring) {
176 SystemTray* tray = GetSystemTray();
177 ASSERT_TRUE(tray->GetWidget());
178 // At the beginning the tray coloring is not active.
179 ASSERT_FALSE(tray->draw_background_as_active());
181 // Showing the system bubble should show the background as active.
182 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
183 ASSERT_TRUE(tray->draw_background_as_active());
185 // Closing the system menu should change the coloring back to normal.
186 ASSERT_TRUE(tray->CloseSystemBubble());
187 RunAllPendingInMessageLoop();
188 ASSERT_FALSE(tray->draw_background_as_active());
191 // Closing the system bubble through an alignment change should change the
192 // system tray coloring back to normal.
193 TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) {
194 SystemTray* tray = GetSystemTray();
195 ASSERT_TRUE(tray->GetWidget());
196 ShelfLayoutManager* manager =
197 Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
198 manager->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
199 // At the beginning the tray coloring is not active.
200 ASSERT_FALSE(tray->draw_background_as_active());
202 // Showing the system bubble should show the background as active.
203 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
204 ASSERT_TRUE(tray->draw_background_as_active());
206 // Changing the alignment should close the system bubble and change the
207 // background color.
208 manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
209 ASSERT_FALSE(tray->draw_background_as_active());
210 RunAllPendingInMessageLoop();
211 // The bubble should already be closed by now.
212 ASSERT_FALSE(tray->CloseSystemBubble());
215 TEST_F(SystemTrayTest, SystemTrayTestItems) {
216 SystemTray* tray = GetSystemTray();
217 ASSERT_TRUE(tray->GetWidget());
219 TestItem* test_item = new TestItem;
220 TestItem* detailed_item = new TestItem;
221 tray->AddTrayItem(test_item);
222 tray->AddTrayItem(detailed_item);
224 // Check items have been added
225 const std::vector<SystemTrayItem*>& items = tray->GetTrayItems();
226 ASSERT_TRUE(
227 std::find(items.begin(), items.end(), test_item) != items.end());
228 ASSERT_TRUE(
229 std::find(items.begin(), items.end(), detailed_item) != items.end());
231 // Ensure the tray views are created.
232 ASSERT_TRUE(test_item->tray_view() != NULL);
233 ASSERT_TRUE(detailed_item->tray_view() != NULL);
235 // Ensure a default views are created.
236 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
237 ASSERT_TRUE(test_item->default_view() != NULL);
238 ASSERT_TRUE(detailed_item->default_view() != NULL);
240 // Show the detailed view, ensure it's created and the default view destroyed.
241 tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
242 RunAllPendingInMessageLoop();
243 ASSERT_TRUE(test_item->default_view() == NULL);
244 ASSERT_TRUE(detailed_item->detailed_view() != NULL);
246 // Show the default view, ensure it's created and the detailed view destroyed.
247 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
248 RunAllPendingInMessageLoop();
249 ASSERT_TRUE(test_item->default_view() != NULL);
250 ASSERT_TRUE(detailed_item->detailed_view() == NULL);
253 TEST_F(SystemTrayTest, SystemTrayNoViewItems) {
254 SystemTray* tray = GetSystemTray();
255 ASSERT_TRUE(tray->GetWidget());
257 // Verify that no crashes occur on items lacking some views.
258 TestNoViewItem* no_view_item = new TestNoViewItem;
259 tray->AddTrayItem(no_view_item);
260 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
261 tray->ShowDetailedView(no_view_item, 0, false, BUBBLE_USE_EXISTING);
262 RunAllPendingInMessageLoop();
265 TEST_F(SystemTrayTest, TrayWidgetAutoResizes) {
266 SystemTray* tray = GetSystemTray();
267 ASSERT_TRUE(tray->GetWidget());
269 // Add an initial tray item so that the tray gets laid out correctly.
270 TestItem* initial_item = new TestItem;
271 tray->AddTrayItem(initial_item);
273 gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
275 TestItem* new_item = new TestItem;
276 tray->AddTrayItem(new_item);
278 gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
280 // Adding the new item should change the size of the tray.
281 EXPECT_NE(initial_size.ToString(), new_size.ToString());
283 // Hiding the tray view of the new item should also change the size of the
284 // tray.
285 new_item->tray_view()->SetVisible(false);
286 EXPECT_EQ(initial_size.ToString(),
287 tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
289 new_item->tray_view()->SetVisible(true);
290 EXPECT_EQ(new_size.ToString(),
291 tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
294 TEST_F(SystemTrayTest, SystemTrayNotifications) {
295 SystemTray* tray = GetSystemTray();
296 ASSERT_TRUE(tray->GetWidget());
298 TestItem* test_item = new TestItem;
299 TestItem* detailed_item = new TestItem;
300 tray->AddTrayItem(test_item);
301 tray->AddTrayItem(detailed_item);
303 // Ensure the tray views are created.
304 ASSERT_TRUE(test_item->tray_view() != NULL);
305 ASSERT_TRUE(detailed_item->tray_view() != NULL);
307 // Ensure a notification view is created.
308 tray->ShowNotificationView(test_item);
309 ASSERT_TRUE(test_item->notification_view() != NULL);
311 // Show the default view, notification view should remain.
312 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
313 RunAllPendingInMessageLoop();
314 ASSERT_TRUE(test_item->notification_view() != NULL);
316 // Show the detailed view, ensure the notification view remains.
317 tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
318 RunAllPendingInMessageLoop();
319 ASSERT_TRUE(detailed_item->detailed_view() != NULL);
320 ASSERT_TRUE(test_item->notification_view() != NULL);
322 // Hide the detailed view, ensure the notification view still exists.
323 ASSERT_TRUE(tray->CloseSystemBubble());
324 RunAllPendingInMessageLoop();
325 ASSERT_TRUE(detailed_item->detailed_view() == NULL);
326 ASSERT_TRUE(test_item->notification_view() != NULL);
329 TEST_F(SystemTrayTest, BubbleCreationTypesTest) {
330 SystemTray* tray = GetSystemTray();
331 ASSERT_TRUE(tray->GetWidget());
333 TestItem* test_item = new TestItem;
334 tray->AddTrayItem(test_item);
336 // Ensure the tray views are created.
337 ASSERT_TRUE(test_item->tray_view() != NULL);
339 // Show the default view, ensure the notification view is destroyed.
340 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
341 RunAllPendingInMessageLoop();
343 views::Widget* widget = test_item->default_view()->GetWidget();
344 gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen();
346 tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING);
347 RunAllPendingInMessageLoop();
349 EXPECT_FALSE(test_item->default_view());
351 EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view()->GetWidget()->
352 GetWindowBoundsInScreen().ToString());
353 EXPECT_EQ(widget, test_item->detailed_view()->GetWidget());
355 tray->ShowDefaultView(BUBBLE_USE_EXISTING);
356 RunAllPendingInMessageLoop();
358 EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view()->GetWidget()->
359 GetWindowBoundsInScreen().ToString());
360 EXPECT_EQ(widget, test_item->default_view()->GetWidget());
363 // Tests that the tray is laid out properly and is fully contained within
364 // the shelf.
365 TEST_F(SystemTrayTest, TrayBoundsInWidget) {
366 ShelfLayoutManager* manager =
367 Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
368 StatusAreaWidget* widget =
369 Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
370 SystemTray* tray = widget->system_tray();
372 // Test in bottom alignment.
373 manager->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
374 gfx::Rect window_bounds = widget->GetWindowBoundsInScreen();
375 gfx::Rect tray_bounds = tray->GetBoundsInScreen();
376 EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
377 EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
378 EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
379 EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
381 // Test in the left alignment.
382 manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
383 window_bounds = widget->GetWindowBoundsInScreen();
384 tray_bounds = tray->GetBoundsInScreen();
385 EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
386 EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
387 EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
388 EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
390 // Test in the right alignment.
391 manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
392 window_bounds = widget->GetWindowBoundsInScreen();
393 tray_bounds = tray->GetBoundsInScreen();
394 EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
395 EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
396 EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
397 EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
400 TEST_F(SystemTrayTest, PersistentBubble) {
401 SystemTray* tray = GetSystemTray();
402 ASSERT_TRUE(tray->GetWidget());
404 TestItem* test_item = new TestItem;
405 tray->AddTrayItem(test_item);
407 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
409 // Tests for usual default view.
410 // Activating window.
411 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
412 ASSERT_TRUE(tray->HasSystemBubble());
413 wm::ActivateWindow(window.get());
414 base::RunLoop().RunUntilIdle();
415 ASSERT_FALSE(tray->HasSystemBubble());
417 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
418 ASSERT_TRUE(tray->HasSystemBubble());
420 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
421 gfx::Point(5, 5));
422 generator.ClickLeftButton();
423 ASSERT_FALSE(tray->HasSystemBubble());
426 // Same tests for persistent default view.
427 tray->ShowPersistentDefaultView();
428 ASSERT_TRUE(tray->HasSystemBubble());
429 wm::ActivateWindow(window.get());
430 base::RunLoop().RunUntilIdle();
431 ASSERT_TRUE(tray->HasSystemBubble());
434 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
435 gfx::Point(5, 5));
436 generator.ClickLeftButton();
437 ASSERT_TRUE(tray->HasSystemBubble());
441 #if defined(OS_CHROMEOS)
442 // Accessibility/Settings tray items are available only on cros.
443 #define MAYBE_WithSystemModal WithSystemModal
444 #else
445 #define MAYBE_WithSystemModal DISABLED_WithSystemModal
446 #endif
447 TEST_F(SystemTrayTest, MAYBE_WithSystemModal) {
448 // Check if the accessibility item is created even with system modal
449 // dialog.
450 Shell::GetInstance()->accessibility_delegate()->SetVirtualKeyboardEnabled(
451 true);
452 views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
453 new ModalWidgetDelegate(),
454 Shell::GetPrimaryRootWindow(),
455 gfx::Rect(0, 0, 100, 100));
456 widget->Show();
458 SystemTray* tray = GetSystemTray();
459 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
461 ASSERT_TRUE(tray->HasSystemBubble());
462 const views::View* accessibility =
463 tray->GetSystemBubble()->bubble_view()->GetViewByID(
464 test::kAccessibilityTrayItemViewId);
465 ASSERT_TRUE(accessibility);
466 EXPECT_TRUE(accessibility->visible());
467 EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetViewByID(
468 test::kSettingsTrayItemViewId));
470 widget->Close();
472 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
473 // System modal is gone. The bubble should now contains settings
474 // as well.
475 accessibility = tray->GetSystemBubble()->bubble_view()->GetViewByID(
476 test::kAccessibilityTrayItemViewId);
477 ASSERT_TRUE(accessibility);
478 EXPECT_TRUE(accessibility->visible());
480 const views::View* settings =
481 tray->GetSystemBubble()->bubble_view()->GetViewByID(
482 test::kSettingsTrayItemViewId);
483 ASSERT_TRUE(settings);
484 EXPECT_TRUE(settings->visible());
487 // Tests that if SetVisible(true) is called while animating to hidden that the
488 // tray becomes visible, and stops animating to hidden.
489 TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) {
490 SystemTray* tray = GetSystemTray();
491 ASSERT_TRUE(tray->visible());
493 scoped_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration;
494 animation_duration.reset(
495 new ui::ScopedAnimationDurationScaleMode(
496 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
497 tray->SetVisible(false);
498 EXPECT_TRUE(tray->visible());
499 EXPECT_EQ(0.0f, tray->layer()->GetTargetOpacity());
501 tray->SetVisible(true);
502 animation_duration.reset();
503 tray->layer()->GetAnimator()->StopAnimating();
504 EXPECT_TRUE(tray->visible());
505 EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity());
508 } // namespace test
509 } // namespace ash