1 // Copyright 2013 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.
7 #include "ash/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shell.h"
11 #include "ash/shell_delegate.h"
12 #include "ash/system/tray/system_tray.h"
13 #include "ash/system/user/tray_user.h"
14 #include "ash/test/ash_test_base.h"
15 #include "ash/test/test_session_state_delegate.h"
16 #include "ash/test/test_shell_delegate.h"
17 #include "base/command_line.h"
18 #include "ui/aura/test/event_generator.h"
19 #include "ui/gfx/animation/animation_container_element.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/widget.h"
23 #if defined(OS_CHROMEOS)
24 #include "ash/system/tray/system_tray_notifier.h"
30 class TrayUserTest : public ash::test::AshTestBase {
35 virtual void SetUp() OVERRIDE;
37 // This has to be called prior to first use with the proper configuration.
38 void InitializeParameters(int users_logged_in, bool multiprofile);
40 // Show the system tray menu using the provided event generator.
41 void ShowTrayMenu(aura::test::EventGenerator* generator);
43 // Move the mouse over the user item.
44 void MoveOverUserItem(aura::test::EventGenerator* generator, int index);
46 // Click on the user item. Note that the tray menu needs to be shown.
47 void ClickUserItem(aura::test::EventGenerator* generator, int index);
49 // Accessors to various system components.
50 ShelfLayoutManager* shelf() { return shelf_; }
51 SystemTray* tray() { return tray_; }
52 ash::test::TestSessionStateDelegate* delegate() { return delegate_; }
53 ash::internal::TrayUser* tray_user(int index) { return tray_user_[index]; }
56 ShelfLayoutManager* shelf_;
58 ash::test::TestSessionStateDelegate* delegate_;
59 // Note that the ownership of these items is on the shelf.
60 std::vector<ash::internal::TrayUser*> tray_user_;
62 DISALLOW_COPY_AND_ASSIGN(TrayUserTest);
65 TrayUserTest::TrayUserTest()
71 void TrayUserTest::SetUp() {
72 ash::test::AshTestBase::SetUp();
73 shelf_ = Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
74 tray_ = Shell::GetPrimaryRootWindowController()->GetSystemTray();
75 delegate_ = static_cast<ash::test::TestSessionStateDelegate*>(
76 ash::Shell::GetInstance()->session_state_delegate());
79 void TrayUserTest::InitializeParameters(int users_logged_in,
82 shelf()->LayoutShelf();
83 shelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
85 // Set our default assumptions. Note that it is sufficient to set these
86 // after everything was created.
87 delegate_->set_logged_in_users(users_logged_in);
88 ash::test::TestShellDelegate* shell_delegate =
89 static_cast<ash::test::TestShellDelegate*>(
90 ash::Shell::GetInstance()->delegate());
91 shell_delegate->set_multi_profiles_enabled(multiprofile);
93 // Instead of using the existing tray panels we create new ones which makes
95 // Note that we create one more element then there can be users to show a
97 for (int i = 0; i <= delegate_->GetMaximumNumberOfLoggedInUsers(); i++) {
98 tray_user_.push_back(new ash::internal::TrayUser(tray_, i));
99 tray_->AddTrayItem(tray_user_[i]);
103 void TrayUserTest::ShowTrayMenu(aura::test::EventGenerator* generator) {
104 gfx::Point center = tray()->GetBoundsInScreen().CenterPoint();
106 generator->MoveMouseTo(center.x(), center.y());
107 EXPECT_FALSE(tray()->IsAnyBubbleVisible());
108 generator->ClickLeftButton();
111 void TrayUserTest::MoveOverUserItem(aura::test::EventGenerator* generator,
114 tray_user(index)->GetUserPanelBoundsInScreenForTest().CenterPoint();
116 generator->MoveMouseTo(center.x(), center.y());
119 void TrayUserTest::ClickUserItem(aura::test::EventGenerator* generator,
121 MoveOverUserItem(generator, index);
122 generator->ClickLeftButton();
125 // Make sure that in single user mode the user panel cannot be activated and no
126 // separators are being created.
127 TEST_F(TrayUserTest, SingleUserModeDoesNotAllowAddingUser) {
128 InitializeParameters(1, false);
130 // Move the mouse over the status area and click to open the status menu.
131 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
133 EXPECT_FALSE(tray()->IsAnyBubbleVisible());
135 for (int i = 0; i <= delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
136 EXPECT_EQ(ash::internal::TrayUser::HIDDEN,
137 tray_user(i)->GetStateForTest());
139 ShowTrayMenu(&generator);
141 EXPECT_TRUE(tray()->HasSystemBubble());
142 EXPECT_TRUE(tray()->IsAnyBubbleVisible());
144 for (int i = 0; i <= delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
145 EXPECT_EQ(i == 0 ? ash::internal::TrayUser::SHOWN :
146 ash::internal::TrayUser::HIDDEN,
147 tray_user(i)->GetStateForTest());
149 tray()->CloseSystemBubble();
152 #if defined(OS_CHROMEOS)
153 // Make sure that in multi user mode the user panel can be activated and there
154 // will be one panel for each user plus a separator.
155 // Note: the mouse watcher (for automatic closing upon leave) cannot be tested
156 // here since it does not work with the event system in unit tests.
157 TEST_F(TrayUserTest, MutiUserModeDoesNotAllowToAddUser) {
158 InitializeParameters(1, true);
160 // Move the mouse over the status area and click to open the status menu.
161 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
162 generator.set_async(false);
164 int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
165 // Checking now for each amount of users that the correct is done.
166 for (int j = 1; j < max_users; j++) {
167 // Set the number of logged in users.
168 delegate()->set_logged_in_users(j);
170 // Verify that nothing is shown.
171 EXPECT_FALSE(tray()->IsAnyBubbleVisible());
172 for (int i = 0; i <= max_users; i++)
173 EXPECT_FALSE(tray_user(i)->GetStateForTest());
175 // After clicking on the tray the menu should get shown and for each logged
176 // in user we should get a visible item. In addition, the separator should
177 // show up when we reach more then one user.
178 ShowTrayMenu(&generator);
180 EXPECT_TRUE(tray()->HasSystemBubble());
181 EXPECT_TRUE(tray()->IsAnyBubbleVisible());
182 for (int i = 0; i < max_users; i++) {
183 EXPECT_EQ(i < j ? ash::internal::TrayUser::SHOWN :
184 ash::internal::TrayUser::HIDDEN,
185 tray_user(i)->GetStateForTest());
188 // Check the visibility of the separator.
189 EXPECT_EQ(j > 1 ? ash::internal::TrayUser::SEPARATOR :
190 ash::internal::TrayUser::HIDDEN,
191 tray_user(max_users)->GetStateForTest());
193 // Move the mouse over the user item and it should hover.
194 MoveOverUserItem(&generator, 0);
195 EXPECT_EQ(ash::internal::TrayUser::HOVERED,
196 tray_user(0)->GetStateForTest());
197 for (int i = 1; i < max_users; i++) {
198 EXPECT_EQ(i < j ? ash::internal::TrayUser::SHOWN :
199 ash::internal::TrayUser::HIDDEN,
200 tray_user(i)->GetStateForTest());
203 // Check that clicking the button allows to add item if we have still room
204 // for one more user.
205 ClickUserItem(&generator, 0);
206 EXPECT_EQ(j == max_users ?
207 ash::internal::TrayUser::ACTIVE_BUT_DISABLED :
208 ash::internal::TrayUser::ACTIVE,
209 tray_user(0)->GetStateForTest());
211 // Click the button again to see that the menu goes away.
212 ClickUserItem(&generator, 0);
213 EXPECT_EQ(ash::internal::TrayUser::HOVERED,
214 tray_user(0)->GetStateForTest());
216 // Close and check that everything is deleted.
217 tray()->CloseSystemBubble();
218 EXPECT_FALSE(tray()->IsAnyBubbleVisible());
219 for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
220 EXPECT_EQ(ash::internal::TrayUser::HIDDEN,
221 tray_user(i)->GetStateForTest());
225 // Make sure that user changing gets properly executed.
226 TEST_F(TrayUserTest, MutiUserModeButtonClicks) {
228 InitializeParameters(2, true);
229 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
230 ShowTrayMenu(&generator);
232 // Switch to a new user - which has a capitalized name.
233 ClickUserItem(&generator, 1);
234 EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserID(1));
235 // Since the name is capitalized, the email should be different then the
237 EXPECT_NE(delegate()->get_activated_user(), delegate()->GetUserEmail(1));
238 tray()->CloseSystemBubble();
241 // Make sure that we show items for all users in the tray accordingly.
242 TEST_F(TrayUserTest, CheckTrayUserItems) {
243 InitializeParameters(1, true);
245 int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
246 // Checking now for each amount of users that the proper items are visible in
247 // the tray. The proper item is hereby:
251 // 0 -> Separator (never shown)
252 // Note: Tray items are required to populate system tray items as well as the
253 // system tray menu. The system tray menu changes it's appearance with the
254 // addition of more users, but the system tray does not create new items after
255 // it got created. The logic to know if an item is present, not present or
256 // even "only" a "separator" is inside the tray user items. This test tries
257 // to test as close as possible the "real thing" and as such the break is
259 for (int j = 1; j <= max_users; j++) {
260 // We simulate the user addition by telling the delegate the new number of
261 // users, then change all user tray items and finally tell the tray to
263 delegate()->set_logged_in_users(j);
264 Shell::GetInstance()->system_tray_notifier()->NotifyUserAddedToSession();
267 // Check that the tray items are being shown in the reverse order.
268 for (int i = 0; i <= max_users; i++) {
269 gfx::Rect rect = tray()->
270 GetTrayItemViewForTest(tray_user(i))->GetBoundsInScreen();
271 if (max_users - i < j)
272 EXPECT_FALSE(rect.IsEmpty());
274 EXPECT_TRUE(rect.IsEmpty());
278 // Click on the last item to see that the user changes.
279 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
280 generator.set_async(false);
282 // Switch to a new user - again, note that we have to click on the reverse
283 // item in the list (1 -> user 3).
285 tray()->GetTrayItemViewForTest(tray_user(1))->
286 GetBoundsInScreen().CenterPoint();
288 generator.MoveMouseTo(point.x(), point.y());
289 generator.ClickLeftButton();
290 EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserID(2));
295 } // namespace internal