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"
9 #include "ash/root_window_controller.h"
10 #include "ash/system/status_area_widget.h"
11 #include "ash/system/tray/system_tray_item.h"
12 #include "ash/test/ash_test_base.h"
13 #include "base/utf_string_conversions.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/layout/fill_layout.h"
16 #include "ui/views/view.h"
17 #include "ui/views/widget/widget.h"
24 SystemTray
* GetSystemTray() {
25 return Shell::GetPrimaryRootWindowController()->status_area_widget()->
29 // Trivial item implementation that tracks its views for testing.
30 class TestItem
: public SystemTrayItem
{
32 TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL
) {}
34 virtual views::View
* CreateTrayView(user::LoginStatus status
) {
35 tray_view_
= new views::View
;
36 // Add a label so it has non-zero width.
37 tray_view_
->SetLayoutManager(new views::FillLayout
);
38 tray_view_
->AddChildView(new views::Label(UTF8ToUTF16("Tray")));
42 virtual views::View
* CreateDefaultView(user::LoginStatus status
) {
43 default_view_
= new views::View
;
44 default_view_
->SetLayoutManager(new views::FillLayout
);
45 default_view_
->AddChildView(new views::Label(UTF8ToUTF16("Default")));
49 virtual views::View
* CreateDetailedView(user::LoginStatus status
) {
50 detailed_view_
= new views::View
;
51 detailed_view_
->SetLayoutManager(new views::FillLayout
);
52 detailed_view_
->AddChildView(new views::Label(UTF8ToUTF16("Detailed")));
53 return detailed_view_
;
56 virtual views::View
* CreateNotificationView(user::LoginStatus status
) {
57 notification_view_
= new views::View
;
58 return notification_view_
;
61 virtual void DestroyTrayView() {
65 virtual void DestroyDefaultView() {
69 virtual void DestroyDetailedView() {
70 detailed_view_
= NULL
;
73 virtual void DestroyNotificationView() {
74 notification_view_
= NULL
;
77 virtual void UpdateAfterLoginStatusChange(user::LoginStatus status
) {
80 views::View
* tray_view() const { return tray_view_
; }
81 views::View
* default_view() const { return default_view_
; }
82 views::View
* detailed_view() const { return detailed_view_
; }
83 views::View
* notification_view() const { return notification_view_
; }
86 views::View
* tray_view_
;
87 views::View
* default_view_
;
88 views::View
* detailed_view_
;
89 views::View
* notification_view_
;
92 // Trivial item implementation that returns NULL from tray/default/detailed view
94 class TestNoViewItem
: public SystemTrayItem
{
96 TestNoViewItem() : SystemTrayItem(GetSystemTray()) {}
98 virtual views::View
* CreateTrayView(user::LoginStatus status
) OVERRIDE
{
102 virtual views::View
* CreateDefaultView(user::LoginStatus status
) OVERRIDE
{
106 virtual views::View
* CreateDetailedView(user::LoginStatus status
) OVERRIDE
{
110 virtual views::View
* CreateNotificationView(
111 user::LoginStatus status
) OVERRIDE
{
115 virtual void DestroyTrayView() OVERRIDE
{}
116 virtual void DestroyDefaultView() OVERRIDE
{}
117 virtual void DestroyDetailedView() OVERRIDE
{}
118 virtual void DestroyNotificationView() OVERRIDE
{}
119 virtual void UpdateAfterLoginStatusChange(user::LoginStatus status
) OVERRIDE
{
125 typedef AshTestBase SystemTrayTest
;
127 TEST_F(SystemTrayTest
, SystemTrayDefaultView
) {
128 SystemTray
* tray
= GetSystemTray();
129 ASSERT_TRUE(tray
->GetWidget());
131 tray
->ShowDefaultView(BUBBLE_CREATE_NEW
);
133 // Ensure that closing the bubble destroys it.
134 ASSERT_TRUE(tray
->CloseBubbleForTest());
135 RunAllPendingInMessageLoop();
136 ASSERT_FALSE(tray
->CloseBubbleForTest());
139 TEST_F(SystemTrayTest
, SystemTrayTestItems
) {
140 SystemTray
* tray
= GetSystemTray();
141 ASSERT_TRUE(tray
->GetWidget());
143 TestItem
* test_item
= new TestItem
;
144 TestItem
* detailed_item
= new TestItem
;
145 tray
->AddTrayItem(test_item
);
146 tray
->AddTrayItem(detailed_item
);
148 // Ensure the tray views are created.
149 ASSERT_TRUE(test_item
->tray_view() != NULL
);
150 ASSERT_TRUE(detailed_item
->tray_view() != NULL
);
152 // Ensure a default views are created.
153 tray
->ShowDefaultView(BUBBLE_CREATE_NEW
);
154 ASSERT_TRUE(test_item
->default_view() != NULL
);
155 ASSERT_TRUE(detailed_item
->default_view() != NULL
);
157 // Show the detailed view, ensure it's created and the default view destroyed.
158 tray
->ShowDetailedView(detailed_item
, 0, false, BUBBLE_CREATE_NEW
);
159 RunAllPendingInMessageLoop();
160 ASSERT_TRUE(test_item
->default_view() == NULL
);
161 ASSERT_TRUE(detailed_item
->detailed_view() != NULL
);
163 // Show the default view, ensure it's created and the detailed view destroyed.
164 tray
->ShowDefaultView(BUBBLE_CREATE_NEW
);
165 RunAllPendingInMessageLoop();
166 ASSERT_TRUE(test_item
->default_view() != NULL
);
167 ASSERT_TRUE(detailed_item
->detailed_view() == NULL
);
170 TEST_F(SystemTrayTest
, SystemTrayNoViewItems
) {
171 SystemTray
* tray
= GetSystemTray();
172 ASSERT_TRUE(tray
->GetWidget());
174 // Verify that no crashes occur on items lacking some views.
175 TestNoViewItem
* no_view_item
= new TestNoViewItem
;
176 tray
->AddTrayItem(no_view_item
);
177 tray
->ShowDefaultView(BUBBLE_CREATE_NEW
);
178 tray
->ShowDetailedView(no_view_item
, 0, false, BUBBLE_USE_EXISTING
);
179 RunAllPendingInMessageLoop();
182 TEST_F(SystemTrayTest
, TrayWidgetAutoResizes
) {
183 SystemTray
* tray
= GetSystemTray();
184 ASSERT_TRUE(tray
->GetWidget());
186 // Add an initial tray item so that the tray gets laid out correctly.
187 TestItem
* initial_item
= new TestItem
;
188 tray
->AddTrayItem(initial_item
);
190 gfx::Size initial_size
= tray
->GetWidget()->GetWindowBoundsInScreen().size();
192 TestItem
* new_item
= new TestItem
;
193 tray
->AddTrayItem(new_item
);
195 gfx::Size new_size
= tray
->GetWidget()->GetWindowBoundsInScreen().size();
197 // Adding the new item should change the size of the tray.
198 EXPECT_NE(initial_size
.ToString(), new_size
.ToString());
200 // Hiding the tray view of the new item should also change the size of the
202 new_item
->tray_view()->SetVisible(false);
203 EXPECT_EQ(initial_size
.ToString(),
204 tray
->GetWidget()->GetWindowBoundsInScreen().size().ToString());
206 new_item
->tray_view()->SetVisible(true);
207 EXPECT_EQ(new_size
.ToString(),
208 tray
->GetWidget()->GetWindowBoundsInScreen().size().ToString());
211 TEST_F(SystemTrayTest
, SystemTrayNotifications
) {
212 SystemTray
* tray
= GetSystemTray();
213 ASSERT_TRUE(tray
->GetWidget());
215 TestItem
* test_item
= new TestItem
;
216 TestItem
* detailed_item
= new TestItem
;
217 tray
->AddTrayItem(test_item
);
218 tray
->AddTrayItem(detailed_item
);
220 // Ensure the tray views are created.
221 ASSERT_TRUE(test_item
->tray_view() != NULL
);
222 ASSERT_TRUE(detailed_item
->tray_view() != NULL
);
224 // Ensure a notification view is created.
225 tray
->ShowNotificationView(test_item
);
226 ASSERT_TRUE(test_item
->notification_view() != NULL
);
228 // Show the default view, ensure the notification view is destroyed.
229 tray
->ShowDefaultView(BUBBLE_CREATE_NEW
);
230 RunAllPendingInMessageLoop();
231 ASSERT_TRUE(test_item
->notification_view() == NULL
);
233 // Show the detailed view, ensure the notificaiton view is created again.
234 tray
->ShowDetailedView(detailed_item
, 0, false, BUBBLE_CREATE_NEW
);
235 RunAllPendingInMessageLoop();
236 ASSERT_TRUE(detailed_item
->detailed_view() != NULL
);
237 ASSERT_TRUE(test_item
->notification_view() != NULL
);
239 // Hide the detailed view, ensure the notificaiton view still exists.
240 ASSERT_TRUE(tray
->CloseBubbleForTest());
241 RunAllPendingInMessageLoop();
242 ASSERT_TRUE(detailed_item
->detailed_view() == NULL
);
243 ASSERT_TRUE(test_item
->notification_view() != NULL
);
246 TEST_F(SystemTrayTest
, BubbleCreationTypesTest
) {
247 SystemTray
* tray
= GetSystemTray();
248 ASSERT_TRUE(tray
->GetWidget());
250 TestItem
* test_item
= new TestItem
;
251 tray
->AddTrayItem(test_item
);
253 // Ensure the tray views are created.
254 ASSERT_TRUE(test_item
->tray_view() != NULL
);
256 // Show the default view, ensure the notification view is destroyed.
257 tray
->ShowDefaultView(BUBBLE_CREATE_NEW
);
258 RunAllPendingInMessageLoop();
260 views::Widget
* widget
= test_item
->default_view()->GetWidget();
261 gfx::Rect bubble_bounds
= widget
->GetWindowBoundsInScreen();
263 tray
->ShowDetailedView(test_item
, 0, true, BUBBLE_USE_EXISTING
);
264 RunAllPendingInMessageLoop();
266 EXPECT_FALSE(test_item
->default_view());
268 EXPECT_EQ(bubble_bounds
.ToString(), test_item
->detailed_view()->GetWidget()->
269 GetWindowBoundsInScreen().ToString());
270 EXPECT_EQ(widget
, test_item
->detailed_view()->GetWidget());
272 tray
->ShowDefaultView(BUBBLE_USE_EXISTING
);
273 RunAllPendingInMessageLoop();
275 EXPECT_EQ(bubble_bounds
.ToString(), test_item
->default_view()->GetWidget()->
276 GetWindowBoundsInScreen().ToString());
277 EXPECT_EQ(widget
, test_item
->default_view()->GetWidget());