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 "ash/shell.h" 6 #include "ash/shell_window_ids.h" 7 #include "ash/test/ash_test_base.h" 8 #include "ash/test/test_shell_delegate.h" 9 #include "ash/wm/window_util.h" 10 #include "base/command_line.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "ui/app_list/app_list_switches.h" 13 #include "ui/app_list/views/app_list_view.h" 14 #include "ui/aura/test/event_generator.h" 15 #include "ui/aura/test/test_windows.h" 16 #include "ui/aura/window.h" 17 18 namespace ash { 19 20 namespace { 21 22 const int kMinimalCenteredAppListMargin = 10; 23 24 } 25 26 // The parameter is true to test the centered app list, false for normal. 27 // (The test name ends in "/0" for normal, "/1" for centered.) 28 class AppListControllerTest : public test::AshTestBase, 29 public ::testing::WithParamInterface<bool> { 30 public: 31 AppListControllerTest(); 32 virtual ~AppListControllerTest(); 33 virtual void SetUp() OVERRIDE; 34 35 bool IsCentered() const; 36 }; 37 38 AppListControllerTest::AppListControllerTest() { 39 } 40 41 AppListControllerTest::~AppListControllerTest() { 42 } 43 44 void AppListControllerTest::SetUp() { 45 AshTestBase::SetUp(); 46 if (IsCentered()) { 47 CommandLine* command_line = CommandLine::ForCurrentProcess(); 48 command_line->AppendSwitch(app_list::switches::kEnableCenteredAppList); 49 } 50 } 51 52 bool AppListControllerTest::IsCentered() const { 53 return GetParam(); 54 } 55 56 // Tests that app launcher hides when focus moves to a normal window. 57 TEST_P(AppListControllerTest, HideOnFocusOut) { 58 Shell::GetInstance()->ToggleAppList(NULL); 59 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 60 61 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0)); 62 wm::ActivateWindow(window.get()); 63 64 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 65 } 66 67 // Tests that app launcher remains visible when focus is moved to a different 68 // window in kShellWindowId_AppListContainer. 69 TEST_P(AppListControllerTest, RemainVisibleWhenFocusingToApplistContainer) { 70 Shell::GetInstance()->ToggleAppList(NULL); 71 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 72 73 aura::Window* applist_container = Shell::GetContainer( 74 Shell::GetPrimaryRootWindow(), kShellWindowId_AppListContainer); 75 scoped_ptr<aura::Window> window( 76 aura::test::CreateTestWindowWithId(0, applist_container)); 77 wm::ActivateWindow(window.get()); 78 79 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 80 } 81 82 // Tests that clicking outside the app-list bubble closes it. 83 TEST_P(AppListControllerTest, ClickOutsideBubbleClosesBubble) { 84 Shell* shell = Shell::GetInstance(); 85 shell->ToggleAppList(NULL); 86 87 aura::Window* app_window = shell->GetAppListWindow(); 88 ASSERT_TRUE(app_window); 89 aura::test::EventGenerator generator(shell->GetPrimaryRootWindow(), 90 app_window); 91 // Click on the bubble itself. The bubble should remain visible. 92 generator.ClickLeftButton(); 93 EXPECT_TRUE(shell->GetAppListTargetVisibility()); 94 95 // Click outside the bubble. This should close it. 96 gfx::Rect app_window_bounds = app_window->GetBoundsInRootWindow(); 97 gfx::Point point_outside = 98 gfx::Point(app_window_bounds.right(), app_window_bounds.y()) + 99 gfx::Vector2d(10, 0); 100 EXPECT_TRUE(shell->GetPrimaryRootWindow()->bounds().Contains(point_outside)); 101 generator.MoveMouseToInHost(point_outside); 102 generator.ClickLeftButton(); 103 EXPECT_FALSE(shell->GetAppListTargetVisibility()); 104 } 105 106 // Tests that clicking outside the app-list bubble closes it. 107 TEST_P(AppListControllerTest, TapOutsideBubbleClosesBubble) { 108 Shell* shell = Shell::GetInstance(); 109 shell->ToggleAppList(NULL); 110 111 aura::Window* app_window = shell->GetAppListWindow(); 112 ASSERT_TRUE(app_window); 113 gfx::Rect app_window_bounds = app_window->GetBoundsInRootWindow(); 114 115 aura::test::EventGenerator generator(shell->GetPrimaryRootWindow()); 116 // Click on the bubble itself. The bubble should remain visible. 117 generator.GestureTapAt(app_window_bounds.CenterPoint()); 118 EXPECT_TRUE(shell->GetAppListTargetVisibility()); 119 120 // Click outside the bubble. This should close it. 121 gfx::Point point_outside = 122 gfx::Point(app_window_bounds.right(), app_window_bounds.y()) + 123 gfx::Vector2d(10, 0); 124 EXPECT_TRUE(shell->GetPrimaryRootWindow()->bounds().Contains(point_outside)); 125 generator.GestureTapAt(point_outside); 126 EXPECT_FALSE(shell->GetAppListTargetVisibility()); 127 } 128 129 // Tests opening the app launcher on a non-primary display, then deleting the 130 // display. 131 TEST_P(AppListControllerTest, NonPrimaryDisplay) { 132 if (!SupportsMultipleDisplays()) 133 return; 134 135 // Set up a screen with two displays (horizontally adjacent). 136 UpdateDisplay("800x600,800x600"); 137 138 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 139 ASSERT_EQ(2u, root_windows.size()); 140 aura::Window* secondary_window = root_windows[1]; 141 EXPECT_EQ("800,0 800x600", secondary_window->GetBoundsInScreen().ToString()); 142 143 Shell::GetInstance()->ToggleAppList(secondary_window); 144 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 145 146 // Remove the secondary display. Shouldn't crash (http://crbug.com/368990). 147 UpdateDisplay("800x600"); 148 149 // Updating the displays should close the app list. 150 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 151 } 152 153 // Tests opening the app launcher on a tiny display that is too small to contain 154 // it. 155 TEST_P(AppListControllerTest, TinyDisplay) { 156 // Don't test this for the non-centered app list case; it isn't designed for 157 // small displays. The most common case of a small display --- when the 158 // virtual keyboard is open --- switches into the centered app list mode, so 159 // we just want to run this test in that case. 160 if (!IsCentered()) 161 return; 162 163 // UpdateDisplay is not supported in this case, so just skip the test. 164 if (!SupportsHostWindowResize()) 165 return; 166 167 // Set up a screen with a tiny display (height smaller than the app list). 168 UpdateDisplay("400x300"); 169 170 Shell::GetInstance()->ToggleAppList(NULL); 171 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 172 173 // The top of the app list should be on-screen (even if the bottom is not). 174 // We need to manually calculate the Y coordinate of the top of the app list 175 // from the anchor (center) and height. There isn't a bounds rect that gives 176 // the actual app list position (the widget bounds include the bubble border 177 // which is much bigger than the actual app list size). 178 app_list::AppListView* app_list = Shell::GetInstance()->GetAppListView(); 179 int app_list_view_top = 180 app_list->anchor_rect().y() - app_list->bounds().height() / 2; 181 EXPECT_GE(app_list_view_top, kMinimalCenteredAppListMargin); 182 } 183 184 INSTANTIATE_TEST_CASE_P(AppListControllerTestInstance, 185 AppListControllerTest, 186 ::testing::Bool()); 187 188 } // namespace ash 189