Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / ash / system / tray / system_tray_unittest.cc
blob6d0b4d9e822b7b95f94676542b0fc35f533db9d6
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/root_window_controller.h"
10 #include "ash/shelf/shelf_widget.h"
11 #include "ash/shell.h"
12 #include "ash/system/status_area_widget.h"
13 #include "ash/system/tray/system_tray_item.h"
14 #include "ash/test/ash_test_base.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "ui/views/controls/label.h"
17 #include "ui/views/layout/fill_layout.h"
18 #include "ui/views/view.h"
19 #include "ui/views/widget/widget.h"
21 #if defined(OS_WIN)
22 #include "base/win/windows_version.h"
23 #endif
25 namespace ash {
26 namespace test {
28 namespace {
30 const int kStatusTrayOffsetFromScreenEdgeForTest = 4;
32 SystemTray* GetSystemTray() {
33 return Shell::GetPrimaryRootWindowController()->shelf()->
34 status_area_widget()->system_tray();
37 // Trivial item implementation that tracks its views for testing.
38 class TestItem : public SystemTrayItem {
39 public:
40 TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL) {}
42 virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE {
43 tray_view_ = new views::View;
44 // Add a label so it has non-zero width.
45 tray_view_->SetLayoutManager(new views::FillLayout);
46 tray_view_->AddChildView(new views::Label(UTF8ToUTF16("Tray")));
47 return tray_view_;
50 virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
51 default_view_ = new views::View;
52 default_view_->SetLayoutManager(new views::FillLayout);
53 default_view_->AddChildView(new views::Label(UTF8ToUTF16("Default")));
54 return default_view_;
57 virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE {
58 detailed_view_ = new views::View;
59 detailed_view_->SetLayoutManager(new views::FillLayout);
60 detailed_view_->AddChildView(new views::Label(UTF8ToUTF16("Detailed")));
61 return detailed_view_;
64 virtual views::View* CreateNotificationView(
65 user::LoginStatus status) OVERRIDE {
66 notification_view_ = new views::View;
67 return notification_view_;
70 virtual void DestroyTrayView() OVERRIDE {
71 tray_view_ = NULL;
74 virtual void DestroyDefaultView() OVERRIDE {
75 default_view_ = NULL;
78 virtual void DestroyDetailedView() OVERRIDE {
79 detailed_view_ = NULL;
82 virtual void DestroyNotificationView() OVERRIDE {
83 notification_view_ = NULL;
86 virtual void UpdateAfterLoginStatusChange(
87 user::LoginStatus status) OVERRIDE {
90 views::View* tray_view() const { return tray_view_; }
91 views::View* default_view() const { return default_view_; }
92 views::View* detailed_view() const { return detailed_view_; }
93 views::View* notification_view() const { return notification_view_; }
95 private:
96 views::View* tray_view_;
97 views::View* default_view_;
98 views::View* detailed_view_;
99 views::View* notification_view_;
102 // Trivial item implementation that returns NULL from tray/default/detailed
103 // view creation methods.
104 class TestNoViewItem : public SystemTrayItem {
105 public:
106 TestNoViewItem() : SystemTrayItem(GetSystemTray()) {}
108 virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE {
109 return NULL;
112 virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
113 return NULL;
116 virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE {
117 return NULL;
120 virtual views::View* CreateNotificationView(
121 user::LoginStatus status) OVERRIDE {
122 return NULL;
125 virtual void DestroyTrayView() OVERRIDE {}
126 virtual void DestroyDefaultView() OVERRIDE {}
127 virtual void DestroyDetailedView() OVERRIDE {}
128 virtual void DestroyNotificationView() OVERRIDE {}
129 virtual void UpdateAfterLoginStatusChange(
130 user::LoginStatus status) OVERRIDE {
134 } // namespace
136 typedef AshTestBase SystemTrayTest;
138 TEST_F(SystemTrayTest, SystemTrayDefaultView) {
139 SystemTray* tray = GetSystemTray();
140 ASSERT_TRUE(tray->GetWidget());
142 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
144 // Ensure that closing the bubble destroys it.
145 ASSERT_TRUE(tray->CloseSystemBubble());
146 RunAllPendingInMessageLoop();
147 ASSERT_FALSE(tray->CloseSystemBubble());
150 TEST_F(SystemTrayTest, SystemTrayTestItems) {
151 SystemTray* tray = GetSystemTray();
152 ASSERT_TRUE(tray->GetWidget());
154 TestItem* test_item = new TestItem;
155 TestItem* detailed_item = new TestItem;
156 tray->AddTrayItem(test_item);
157 tray->AddTrayItem(detailed_item);
159 // Check items have been added
160 const std::vector<SystemTrayItem*>& items = tray->GetTrayItems();
161 ASSERT_TRUE(
162 std::find(items.begin(), items.end(), test_item) != items.end());
163 ASSERT_TRUE(
164 std::find(items.begin(), items.end(), detailed_item) != items.end());
166 // Ensure the tray views are created.
167 ASSERT_TRUE(test_item->tray_view() != NULL);
168 ASSERT_TRUE(detailed_item->tray_view() != NULL);
170 // Ensure a default views are created.
171 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
172 ASSERT_TRUE(test_item->default_view() != NULL);
173 ASSERT_TRUE(detailed_item->default_view() != NULL);
175 // Show the detailed view, ensure it's created and the default view destroyed.
176 tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
177 RunAllPendingInMessageLoop();
178 ASSERT_TRUE(test_item->default_view() == NULL);
179 ASSERT_TRUE(detailed_item->detailed_view() != NULL);
181 // Show the default view, ensure it's created and the detailed view destroyed.
182 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
183 RunAllPendingInMessageLoop();
184 ASSERT_TRUE(test_item->default_view() != NULL);
185 ASSERT_TRUE(detailed_item->detailed_view() == NULL);
188 TEST_F(SystemTrayTest, SystemTrayNoViewItems) {
189 SystemTray* tray = GetSystemTray();
190 ASSERT_TRUE(tray->GetWidget());
192 // Verify that no crashes occur on items lacking some views.
193 TestNoViewItem* no_view_item = new TestNoViewItem;
194 tray->AddTrayItem(no_view_item);
195 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
196 tray->ShowDetailedView(no_view_item, 0, false, BUBBLE_USE_EXISTING);
197 RunAllPendingInMessageLoop();
200 TEST_F(SystemTrayTest, TrayWidgetAutoResizes) {
201 SystemTray* tray = GetSystemTray();
202 ASSERT_TRUE(tray->GetWidget());
204 // Add an initial tray item so that the tray gets laid out correctly.
205 TestItem* initial_item = new TestItem;
206 tray->AddTrayItem(initial_item);
208 gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
210 TestItem* new_item = new TestItem;
211 tray->AddTrayItem(new_item);
213 gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
215 // Adding the new item should change the size of the tray.
216 EXPECT_NE(initial_size.ToString(), new_size.ToString());
218 // Hiding the tray view of the new item should also change the size of the
219 // tray.
220 new_item->tray_view()->SetVisible(false);
221 EXPECT_EQ(initial_size.ToString(),
222 tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
224 new_item->tray_view()->SetVisible(true);
225 EXPECT_EQ(new_size.ToString(),
226 tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
229 TEST_F(SystemTrayTest, SystemTrayNotifications) {
230 SystemTray* tray = GetSystemTray();
231 ASSERT_TRUE(tray->GetWidget());
233 TestItem* test_item = new TestItem;
234 TestItem* detailed_item = new TestItem;
235 tray->AddTrayItem(test_item);
236 tray->AddTrayItem(detailed_item);
238 // Ensure the tray views are created.
239 ASSERT_TRUE(test_item->tray_view() != NULL);
240 ASSERT_TRUE(detailed_item->tray_view() != NULL);
242 // Ensure a notification view is created.
243 tray->ShowNotificationView(test_item);
244 ASSERT_TRUE(test_item->notification_view() != NULL);
246 // Show the default view, notification view should remain.
247 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
248 RunAllPendingInMessageLoop();
249 ASSERT_TRUE(test_item->notification_view() != NULL);
251 // Show the detailed view, ensure the notificaiton view remains.
252 tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
253 RunAllPendingInMessageLoop();
254 ASSERT_TRUE(detailed_item->detailed_view() != NULL);
255 ASSERT_TRUE(test_item->notification_view() != NULL);
257 // Hide the detailed view, ensure the notification view still exists.
258 ASSERT_TRUE(tray->CloseSystemBubble());
259 RunAllPendingInMessageLoop();
260 ASSERT_TRUE(detailed_item->detailed_view() == NULL);
261 ASSERT_TRUE(test_item->notification_view() != NULL);
264 TEST_F(SystemTrayTest, BubbleCreationTypesTest) {
265 SystemTray* tray = GetSystemTray();
266 ASSERT_TRUE(tray->GetWidget());
268 TestItem* test_item = new TestItem;
269 tray->AddTrayItem(test_item);
271 // Ensure the tray views are created.
272 ASSERT_TRUE(test_item->tray_view() != NULL);
274 // Show the default view, ensure the notification view is destroyed.
275 tray->ShowDefaultView(BUBBLE_CREATE_NEW);
276 RunAllPendingInMessageLoop();
278 views::Widget* widget = test_item->default_view()->GetWidget();
279 gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen();
281 tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING);
282 RunAllPendingInMessageLoop();
284 EXPECT_FALSE(test_item->default_view());
286 EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view()->GetWidget()->
287 GetWindowBoundsInScreen().ToString());
288 EXPECT_EQ(widget, test_item->detailed_view()->GetWidget());
290 tray->ShowDefaultView(BUBBLE_USE_EXISTING);
291 RunAllPendingInMessageLoop();
293 EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view()->GetWidget()->
294 GetWindowBoundsInScreen().ToString());
295 EXPECT_EQ(widget, test_item->default_view()->GetWidget());
298 // Tests that the tray is laid out properly in the widget to make sure that the
299 // tray extends to the correct edge of the screen.
300 TEST_F(SystemTrayTest, TrayBoundsInWidget) {
301 internal::StatusAreaWidget* widget =
302 Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
303 SystemTray* tray = widget->system_tray();
305 // Test in bottom alignment. Bottom and right edges of the view should be
306 // aligned with the widget.
307 widget->SetShelfAlignment(SHELF_ALIGNMENT_BOTTOM);
308 gfx::Rect window_bounds = widget->GetWindowBoundsInScreen();
309 gfx::Rect tray_bounds = tray->GetBoundsInScreen();
310 EXPECT_EQ(window_bounds.bottom(),
311 tray_bounds.bottom() + kStatusTrayOffsetFromScreenEdgeForTest);
312 EXPECT_EQ(window_bounds.right(), tray_bounds.right());
314 // Test in the top alignment. Top and right edges should match.
315 widget->SetShelfAlignment(SHELF_ALIGNMENT_TOP);
316 window_bounds = widget->GetWindowBoundsInScreen();
317 tray_bounds = tray->GetBoundsInScreen();
318 EXPECT_EQ(window_bounds.y(),
319 tray_bounds.y() - kStatusTrayOffsetFromScreenEdgeForTest);
320 EXPECT_EQ(window_bounds.right(), tray_bounds.right());
322 // Test in the left alignment. Left and bottom edges should match.
323 widget->SetShelfAlignment(SHELF_ALIGNMENT_LEFT);
324 window_bounds = widget->GetWindowBoundsInScreen();
325 tray_bounds = tray->GetBoundsInScreen();
326 EXPECT_EQ(window_bounds.bottom(), tray_bounds.bottom());
327 EXPECT_EQ(window_bounds.x(),
328 tray_bounds.x() - kStatusTrayOffsetFromScreenEdgeForTest);
330 // Test in the right alignment. Right and bottom edges should match.
331 widget->SetShelfAlignment(SHELF_ALIGNMENT_LEFT);
332 window_bounds = widget->GetWindowBoundsInScreen();
333 tray_bounds = tray->GetBoundsInScreen();
334 EXPECT_EQ(window_bounds.bottom(), tray_bounds.bottom());
335 EXPECT_EQ(window_bounds.right(), tray_bounds.right());
338 } // namespace test
339 } // namespace ash