Home | History | Annotate | Download | only in user
      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/system/user/tray_user_separator.h"
     15 #include "ash/test/ash_test_base.h"
     16 #include "ash/test/test_session_state_delegate.h"
     17 #include "ash/test/test_shell_delegate.h"
     18 #include "base/command_line.h"
     19 #include "ui/aura/test/event_generator.h"
     20 #include "ui/gfx/animation/animation_container_element.h"
     21 #include "ui/views/view.h"
     22 #include "ui/views/widget/widget.h"
     23 
     24 #if defined(OS_CHROMEOS)
     25 #include "ash/system/tray/system_tray_notifier.h"
     26 #endif
     27 
     28 namespace ash {
     29 namespace internal {
     30 
     31 class TrayUserTest : public ash::test::AshTestBase {
     32  public:
     33   TrayUserTest();
     34 
     35   // testing::Test:
     36   virtual void SetUp() OVERRIDE;
     37 
     38   // This has to be called prior to first use with the proper configuration.
     39   void InitializeParameters(int users_logged_in, bool multiprofile);
     40 
     41   // Show the system tray menu using the provided event generator.
     42   void ShowTrayMenu(aura::test::EventGenerator* generator);
     43 
     44   // Move the mouse over the user item.
     45   void MoveOverUserItem(aura::test::EventGenerator* generator, int index);
     46 
     47   // Click on the user item. Note that the tray menu needs to be shown.
     48   void ClickUserItem(aura::test::EventGenerator* generator, int index);
     49 
     50   // Accessors to various system components.
     51   ShelfLayoutManager* shelf() { return shelf_; }
     52   SystemTray* tray() { return tray_; }
     53   ash::test::TestSessionStateDelegate* delegate() { return delegate_; }
     54   ash::internal::TrayUser* tray_user(int index) { return tray_user_[index]; }
     55   ash::internal::TrayUserSeparator* tray_user_separator() {
     56     return tray_user_separator_;
     57   }
     58 
     59  private:
     60   ShelfLayoutManager* shelf_;
     61   SystemTray* tray_;
     62   ash::test::TestSessionStateDelegate* delegate_;
     63 
     64   // Note that the ownership of these items is on the shelf.
     65   std::vector<ash::internal::TrayUser*> tray_user_;
     66 
     67   // The separator between the tray users and the rest of the menu.
     68   // Note: The item will get owned by the shelf.
     69   TrayUserSeparator* tray_user_separator_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(TrayUserTest);
     72 };
     73 
     74 #if defined(OS_CHROMEOS)
     75 // The tray user test which tests functionality where multiple tray items are
     76 // visible in the system tray.
     77 class MultiTrayUserTest : public TrayUserTest {
     78  public:
     79   MultiTrayUserTest() {}
     80 
     81   virtual void SetUp() OVERRIDE {
     82     CommandLine* command_line = CommandLine::ForCurrentProcess();
     83     command_line->AppendSwitch(ash::switches::kAshEnableMultiUserTray);
     84     TrayUserTest::SetUp();
     85   }
     86 
     87  private:
     88   DISALLOW_COPY_AND_ASSIGN(MultiTrayUserTest);
     89 };
     90 #endif
     91 
     92 TrayUserTest::TrayUserTest()
     93     : shelf_(NULL),
     94       tray_(NULL),
     95       delegate_(NULL),
     96       tray_user_separator_(NULL) {
     97 }
     98 
     99 void TrayUserTest::SetUp() {
    100   ash::test::AshTestBase::SetUp();
    101   shelf_ = Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
    102   tray_ = Shell::GetPrimaryRootWindowController()->GetSystemTray();
    103   delegate_ = static_cast<ash::test::TestSessionStateDelegate*>(
    104       ash::Shell::GetInstance()->session_state_delegate());
    105 }
    106 
    107 void TrayUserTest::InitializeParameters(int users_logged_in,
    108                                         bool multiprofile) {
    109   // Show the shelf.
    110   shelf()->LayoutShelf();
    111   shelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
    112 
    113   // Set our default assumptions. Note that it is sufficient to set these
    114   // after everything was created.
    115   delegate_->set_logged_in_users(users_logged_in);
    116   ash::test::TestShellDelegate* shell_delegate =
    117       static_cast<ash::test::TestShellDelegate*>(
    118           ash::Shell::GetInstance()->delegate());
    119   shell_delegate->set_multi_profiles_enabled(multiprofile);
    120 
    121   // Instead of using the existing tray panels we create new ones which makes
    122   // the access easier.
    123   for (int i = 0; i < delegate_->GetMaximumNumberOfLoggedInUsers(); i++) {
    124     tray_user_.push_back(new ash::internal::TrayUser(tray_, i));
    125     tray_->AddTrayItem(tray_user_[i]);
    126   }
    127   // We then add also the separator.
    128   tray_user_separator_ = new ash::internal::TrayUserSeparator(tray_);
    129   tray_->AddTrayItem(tray_user_separator_);
    130 }
    131 
    132 void TrayUserTest::ShowTrayMenu(aura::test::EventGenerator* generator) {
    133   gfx::Point center = tray()->GetBoundsInScreen().CenterPoint();
    134 
    135   generator->MoveMouseTo(center.x(), center.y());
    136   EXPECT_FALSE(tray()->IsAnyBubbleVisible());
    137   generator->ClickLeftButton();
    138 }
    139 
    140 void TrayUserTest::MoveOverUserItem(aura::test::EventGenerator* generator,
    141     int index) {
    142   gfx::Point center =
    143       tray_user(index)->GetUserPanelBoundsInScreenForTest().CenterPoint();
    144 
    145   generator->MoveMouseTo(center.x(), center.y());
    146 }
    147 
    148 void TrayUserTest::ClickUserItem(aura::test::EventGenerator* generator,
    149                                  int index) {
    150   MoveOverUserItem(generator, index);
    151   generator->ClickLeftButton();
    152 }
    153 
    154 // Make sure that in single user mode the user panel cannot be activated and no
    155 // separators are being created.
    156 TEST_F(TrayUserTest, SingleUserModeDoesNotAllowAddingUser) {
    157   InitializeParameters(1, false);
    158 
    159   // Move the mouse over the status area and click to open the status menu.
    160   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    161 
    162   EXPECT_FALSE(tray()->IsAnyBubbleVisible());
    163 
    164   for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
    165     EXPECT_EQ(ash::internal::TrayUser::HIDDEN,
    166               tray_user(i)->GetStateForTest());
    167   EXPECT_FALSE(tray_user_separator()->separator_shown());
    168 
    169   ShowTrayMenu(&generator);
    170 
    171   EXPECT_TRUE(tray()->HasSystemBubble());
    172   EXPECT_TRUE(tray()->IsAnyBubbleVisible());
    173 
    174   for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
    175     EXPECT_EQ(i == 0 ? ash::internal::TrayUser::SHOWN :
    176                        ash::internal::TrayUser::HIDDEN,
    177               tray_user(i)->GetStateForTest());
    178   EXPECT_FALSE(tray_user_separator()->separator_shown());
    179   tray()->CloseSystemBubble();
    180 }
    181 
    182 #if defined(OS_CHROMEOS)
    183 // Make sure that in multi user mode the user panel can be activated and there
    184 // will be one panel for each user plus one additional separator at the end.
    185 // Note: the mouse watcher (for automatic closing upon leave) cannot be tested
    186 // here since it does not work with the event system in unit tests.
    187 TEST_F(TrayUserTest, MutiUserModeDoesNotAllowToAddUser) {
    188   InitializeParameters(1, true);
    189 
    190   // Move the mouse over the status area and click to open the status menu.
    191   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    192   generator.set_async(false);
    193 
    194   int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
    195   // Checking now for each amount of users that the correct is done.
    196   for (int j = 1; j < max_users; j++) {
    197     // Set the number of logged in users.
    198     delegate()->set_logged_in_users(j);
    199 
    200     // Verify that nothing is shown.
    201     EXPECT_FALSE(tray()->IsAnyBubbleVisible());
    202     for (int i = 0; i < max_users; i++)
    203       EXPECT_FALSE(tray_user(i)->GetStateForTest());
    204     EXPECT_FALSE(tray_user_separator()->separator_shown());
    205     // After clicking on the tray the menu should get shown and for each logged
    206     // in user we should get a visible item. In addition, the separator should
    207     // show up when we reach more then one user.
    208     ShowTrayMenu(&generator);
    209 
    210     EXPECT_TRUE(tray()->HasSystemBubble());
    211     EXPECT_TRUE(tray()->IsAnyBubbleVisible());
    212     for (int i = 0; i < max_users; i++) {
    213       EXPECT_EQ(i < j ? ash::internal::TrayUser::SHOWN :
    214                         ash::internal::TrayUser::HIDDEN,
    215                 tray_user(i)->GetStateForTest());
    216     }
    217 
    218     // Check the visibility of the separator.
    219     EXPECT_EQ(j > 1 ? true : false, tray_user_separator()->separator_shown());
    220 
    221     // Move the mouse over the user item and it should hover.
    222     MoveOverUserItem(&generator, 0);
    223     EXPECT_EQ(ash::internal::TrayUser::HOVERED,
    224               tray_user(0)->GetStateForTest());
    225     for (int i = 1; i < max_users; i++) {
    226       EXPECT_EQ(i < j ? ash::internal::TrayUser::SHOWN :
    227                         ash::internal::TrayUser::HIDDEN,
    228                 tray_user(i)->GetStateForTest());
    229     }
    230 
    231     // Check that clicking the button allows to add item if we have still room
    232     // for one more user.
    233     ClickUserItem(&generator, 0);
    234     EXPECT_EQ(j == max_users ?
    235                   ash::internal::TrayUser::ACTIVE_BUT_DISABLED :
    236                   ash::internal::TrayUser::ACTIVE,
    237               tray_user(0)->GetStateForTest());
    238 
    239     // Click the button again to see that the menu goes away.
    240     ClickUserItem(&generator, 0);
    241     EXPECT_EQ(ash::internal::TrayUser::HOVERED,
    242               tray_user(0)->GetStateForTest());
    243 
    244     // Close and check that everything is deleted.
    245     tray()->CloseSystemBubble();
    246     EXPECT_FALSE(tray()->IsAnyBubbleVisible());
    247     for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++)
    248       EXPECT_EQ(ash::internal::TrayUser::HIDDEN,
    249                 tray_user(i)->GetStateForTest());
    250   }
    251 }
    252 
    253 // Make sure that user changing gets properly executed.
    254 TEST_F(TrayUserTest, MutiUserModeButtonClicks) {
    255   // Have two users.
    256   InitializeParameters(2, true);
    257   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    258   ShowTrayMenu(&generator);
    259 
    260   // Switch to a new user - which has a capitalized name.
    261   ClickUserItem(&generator, 1);
    262   EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserID(1));
    263   // Since the name is capitalized, the email should be different then the
    264   // user_id.
    265   EXPECT_NE(delegate()->get_activated_user(), delegate()->GetUserEmail(1));
    266   tray()->CloseSystemBubble();
    267 }
    268 
    269 // Make sure that we show items for all users in the tray accordingly.
    270 TEST_F(MultiTrayUserTest, CheckTrayUserItems) {
    271   InitializeParameters(1, true);
    272 
    273   int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
    274   // Checking now for each amount of users that the proper items are visible in
    275   // the tray. The proper item is hereby:
    276   // 2 -> User #1
    277   // 1 -> User #2
    278   // 0 -> User #3
    279   // Note: Tray items are required to populate system tray items as well as the
    280   // system tray menu. The system tray menu changes it's appearance with the
    281   // addition of more users, but the system tray does not create new items after
    282   // it got created.
    283   for (int present_users = 1; present_users <= max_users; ++present_users) {
    284     // We simulate the user addition by telling the delegate the new number of
    285     // users, then change all user tray items and finally tell the tray to
    286     // re-layout itself.
    287     delegate()->set_logged_in_users(present_users);
    288     Shell::GetInstance()->system_tray_notifier()->NotifyUserAddedToSession();
    289     tray()->Layout();
    290 
    291     // Check that the tray items are being shown in the reverse order.
    292     for (int i = 0; i < max_users; i++) {
    293       gfx::Rect rect =
    294           tray()->GetTrayItemViewForTest(tray_user(i))->GetBoundsInScreen();
    295       if (max_users - 1 - i < present_users)
    296         EXPECT_FALSE(rect.IsEmpty());
    297       else
    298         EXPECT_TRUE(rect.IsEmpty());
    299     }
    300   }
    301 
    302   // Click on the last item to see that the user changes.
    303   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
    304   generator.set_async(false);
    305 
    306   // Switch to a new user - again, note that we have to click on the reverse
    307   // item in the list. Since the first clickable item is 1, we get user #2.
    308   gfx::Point point =
    309       tray()->GetTrayItemViewForTest(tray_user(1))->
    310                          GetBoundsInScreen().CenterPoint();
    311 
    312   generator.MoveMouseTo(point.x(), point.y());
    313   generator.ClickLeftButton();
    314   EXPECT_EQ(delegate()->get_activated_user(), delegate()->GetUserID(1));
    315 }
    316 
    317 #endif
    318 
    319 }  // namespace internal
    320 }  // namespace ash
    321