tray_user_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include <vector>
6
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"
22
23#if defined(OS_CHROMEOS)
24#include "ash/system/tray/system_tray_notifier.h"
25#endif
26
27namespace ash {
28namespace internal {
29
30class TrayUserTest : public ash::test::AshTestBase {
31 public:
32  TrayUserTest();
33
34  // testing::Test:
35  virtual void SetUp() OVERRIDE;
36
37  // This has to be called prior to first use with the proper configuration.
38  void InitializeParameters(int users_logged_in, bool multiprofile);
39
40  // Show the system tray menu using the provided event generator.
41  void ShowTrayMenu(aura::test::EventGenerator* generator);
42
43  // Move the mouse over the user item.
44  void MoveOverUserItem(aura::test::EventGenerator* generator, int index);
45
46  // Click on the user item. Note that the tray menu needs to be shown.
47  void ClickUserItem(aura::test::EventGenerator* generator, int index);
48
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]; }
54
55 private:
56  ShelfLayoutManager* shelf_;
57  SystemTray* tray_;
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_;
61
62  DISALLOW_COPY_AND_ASSIGN(TrayUserTest);
63};
64
65TrayUserTest::TrayUserTest()
66    : shelf_(NULL),
67      tray_(NULL),
68      delegate_(NULL) {
69}
70
71void 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());
77}
78
79void TrayUserTest::InitializeParameters(int users_logged_in,
80                                        bool multiprofile) {
81  // Show the shelf.
82  shelf()->LayoutShelf();
83  shelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
84
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);
92
93  // Instead of using the existing tray panels we create new ones which makes
94  // the access easier.
95  // Note that we create one more element then there can be users to show a
96  // separator.
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]);
100  }
101}
102
103void TrayUserTest::ShowTrayMenu(aura::test::EventGenerator* generator) {
104  gfx::Point center = tray()->GetBoundsInScreen().CenterPoint();
105
106  generator->MoveMouseTo(center.x(), center.y());
107  EXPECT_FALSE(tray()->IsAnyBubbleVisible());
108  generator->ClickLeftButton();
109}
110
111void TrayUserTest::MoveOverUserItem(aura::test::EventGenerator* generator,
112    int index) {
113  gfx::Point center =
114      tray_user(index)->GetUserPanelBoundsInScreenForTest().CenterPoint();
115
116  generator->MoveMouseTo(center.x(), center.y());
117}
118
119void TrayUserTest::ClickUserItem(aura::test::EventGenerator* generator,
120                                 int index) {
121  MoveOverUserItem(generator, index);
122  generator->ClickLeftButton();
123}
124
125// Make sure that in single user mode the user panel cannot be activated and no
126// separators are being created.
127TEST_F(TrayUserTest, SingleUserModeDoesNotAllowAddingUser) {
128  InitializeParameters(1, false);
129
130  // Move the mouse over the status area and click to open the status menu.
131  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
132
133  EXPECT_FALSE(tray()->IsAnyBubbleVisible());
134
135  for (int i = 0; i <= delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
136    EXPECT_EQ(ash::internal::TrayUser::HIDDEN,
137              tray_user(i)->GetStateForTest());
138
139  ShowTrayMenu(&generator);
140
141  EXPECT_TRUE(tray()->HasSystemBubble());
142  EXPECT_TRUE(tray()->IsAnyBubbleVisible());
143
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());
148
149  tray()->CloseSystemBubble();
150}
151
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.
157TEST_F(TrayUserTest, MutiUserModeDoesNotAllowToAddUser) {
158  InitializeParameters(1, true);
159
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);
163
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);
169
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());
174
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);
179
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());
186    }
187
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());
192
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());
201    }
202
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());
210
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());
215
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());
222  }
223}
224
225// Make sure that user changing gets properly executed.
226TEST_F(TrayUserTest, MutiUserModeButtonClicks) {
227  // Have two users.
228  InitializeParameters(2, true);
229  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
230  ShowTrayMenu(&generator);
231
232  // Switch to a new user.
233  ClickUserItem(&generator, 1);
234
235  EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserEmail(1));
236  tray()->CloseSystemBubble();
237}
238
239// Make sure that we show items for all users in the tray accordingly.
240TEST_F(TrayUserTest, CheckTrayUserItems) {
241  InitializeParameters(1, true);
242
243  int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
244  // Checking now for each amount of users that the proper items are visible in
245  // the tray. The proper item is hereby:
246  // 3 -> User #1
247  // 2 -> User #2
248  // 1 -> User #3
249  // 0 -> Separator (never shown)
250  // Note: Tray items are required to populate system tray items as well as the
251  // system tray menu. The system tray menu changes it's appearance with the
252  // addition of more users, but the system tray does not create new items after
253  // it got created. The logic to know if an item is present, not present or
254  // even "only" a "separator" is inside the tray user items. This test tries
255  // to test as close as possible the "real thing" and as such the break is
256  // included.
257  for (int j = 1; j <= max_users; j++) {
258    // We simulate the user addition by telling the delegate the new number of
259    // users, then change all user tray items and finally tell the tray to
260    // re-layout itself.
261    delegate()->set_logged_in_users(j);
262    Shell::GetInstance()->system_tray_notifier()->NotifyUserAddedToSession();
263    tray()->Layout();
264
265    // Check that the tray items are being shown in the reverse order.
266    for (int i = 0; i <= max_users; i++) {
267      gfx::Rect rect = tray()->
268          GetTrayItemViewForTest(tray_user(i))->GetBoundsInScreen();
269      if (max_users - i < j)
270        EXPECT_FALSE(rect.IsEmpty());
271      else
272        EXPECT_TRUE(rect.IsEmpty());
273    }
274  }
275
276  // Click on the last item to see that the user changes.
277  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
278  generator.set_async(false);
279
280  // Switch to a new user - again, note that we have to click on the reverse
281  // item in the list (1 -> user 3).
282  gfx::Point point =
283      tray()->GetTrayItemViewForTest(tray_user(1))->
284                         GetBoundsInScreen().CenterPoint();
285
286  generator.MoveMouseTo(point.x(), point.y());
287  generator.ClickLeftButton();
288  EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserEmail(2));
289}
290
291#endif
292
293}  // namespace internal
294}  // namespace ash
295