14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shell.h" 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shell_window_ids.h" 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/test/ash_test_base.h" 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/test/test_shell_delegate.h" 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/wm/window_util.h" 10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/command_line.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/app_list/app_list_switches.h" 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/app_list/views/app_list_view.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/aura/test/test_windows.h" 154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/aura/window.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/events/test/event_generator.h" 174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace ash { 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace { 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kMinimalCenteredAppListMargin = 10; 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// The parameter is true to test the centered app list, false for normal. 27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// (The test name ends in "/0" for normal, "/1" for centered.) 28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class AppListControllerTest : public test::AshTestBase, 29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public ::testing::WithParamInterface<bool> { 30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public: 31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) AppListControllerTest(); 32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) virtual ~AppListControllerTest(); 33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) virtual void SetUp() OVERRIDE; 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool IsCentered() const; 36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}; 37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)AppListControllerTest::AppListControllerTest() { 39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)AppListControllerTest::~AppListControllerTest() { 42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void AppListControllerTest::SetUp() { 45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) AshTestBase::SetUp(); 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (IsCentered()) { 47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) CommandLine* command_line = CommandLine::ForCurrentProcess(); 48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) command_line->AppendSwitch(app_list::switches::kEnableCenteredAppList); 49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool AppListControllerTest::IsCentered() const { 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return GetParam(); 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Tests that app launcher hides when focus moves to a normal window. 57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_P(AppListControllerTest, HideOnFocusOut) { 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Shell::GetInstance()->ShowAppList(NULL); 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0)); 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) wm::ActivateWindow(window.get()); 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Tests that app launcher remains visible when focus is moved to a different 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// window in kShellWindowId_AppListContainer. 69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_P(AppListControllerTest, RemainVisibleWhenFocusingToApplistContainer) { 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Shell::GetInstance()->ShowAppList(NULL); 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) aura::Window* applist_container = Shell::GetContainer( 74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch Shell::GetPrimaryRootWindow(), kShellWindowId_AppListContainer); 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<aura::Window> window( 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) aura::test::CreateTestWindowWithId(0, applist_container)); 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) wm::ActivateWindow(window.get()); 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Tests that clicking outside the app-list bubble closes it. 83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_P(AppListControllerTest, ClickOutsideBubbleClosesBubble) { 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Shell* shell = Shell::GetInstance(); 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) shell->ShowAppList(NULL); 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) aura::Window* app_window = shell->GetAppListWindow(); 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ASSERT_TRUE(app_window); 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ui::test::EventGenerator generator(shell->GetPrimaryRootWindow(), app_window); 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Click on the bubble itself. The bubble should remain visible. 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) generator.ClickLeftButton(); 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(shell->GetAppListTargetVisibility()); 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Click outside the bubble. This should close it. 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect app_window_bounds = app_window->GetBoundsInRootWindow(); 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Point point_outside = 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Point(app_window_bounds.right(), app_window_bounds.y()) + 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Vector2d(10, 0); 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(shell->GetPrimaryRootWindow()->bounds().Contains(point_outside)); 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) generator.MoveMouseToInHost(point_outside); 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) generator.ClickLeftButton(); 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_FALSE(shell->GetAppListTargetVisibility()); 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Tests that clicking outside the app-list bubble closes it. 106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_P(AppListControllerTest, TapOutsideBubbleClosesBubble) { 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Shell* shell = Shell::GetInstance(); 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) shell->ShowAppList(NULL); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) aura::Window* app_window = shell->GetAppListWindow(); 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ASSERT_TRUE(app_window); 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect app_window_bounds = app_window->GetBoundsInRootWindow(); 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ui::test::EventGenerator generator(shell->GetPrimaryRootWindow()); 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Click on the bubble itself. The bubble should remain visible. 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) generator.GestureTapAt(app_window_bounds.CenterPoint()); 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(shell->GetAppListTargetVisibility()); 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Click outside the bubble. This should close it. 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Point point_outside = 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Point(app_window_bounds.right(), app_window_bounds.y()) + 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Vector2d(10, 0); 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(shell->GetPrimaryRootWindow()->bounds().Contains(point_outside)); 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) generator.GestureTapAt(point_outside); 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_FALSE(shell->GetAppListTargetVisibility()); 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Tests opening the app launcher on a non-primary display, then deleting the 129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// display. 130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TEST_P(AppListControllerTest, NonPrimaryDisplay) { 131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!SupportsMultipleDisplays()) 132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Set up a screen with two displays (horizontally adjacent). 135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) UpdateDisplay("800x600,800x600"); 136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ASSERT_EQ(2u, root_windows.size()); 139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) aura::Window* secondary_window = root_windows[1]; 140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) EXPECT_EQ("800,0 800x600", secondary_window->GetBoundsInScreen().ToString()); 141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Shell::GetInstance()->ShowAppList(secondary_window); 143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Remove the secondary display. Shouldn't crash (http://crbug.com/368990). 146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) UpdateDisplay("800x600"); 147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Updating the displays should close the app list. 149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Tests opening the app launcher on a tiny display that is too small to contain 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// it. 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_P(AppListControllerTest, TinyDisplay) { 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Don't test this for the non-centered app list case; it isn't designed for 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // small displays. The most common case of a small display --- when the 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // virtual keyboard is open --- switches into the centered app list mode, so 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // we just want to run this test in that case. 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!IsCentered()) 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // UpdateDisplay is not supported in this case, so just skip the test. 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!SupportsHostWindowResize()) 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Set up a screen with a tiny display (height smaller than the app list). 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UpdateDisplay("400x300"); 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Shell::GetInstance()->ShowAppList(NULL); 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The top of the app list should be on-screen (even if the bottom is not). 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We need to manually calculate the Y coordinate of the top of the app list 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // from the anchor (center) and height. There isn't a bounds rect that gives 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // the actual app list position (the widget bounds include the bubble border 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // which is much bigger than the actual app list size). 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) app_list::AppListView* app_list = Shell::GetInstance()->GetAppListView(); 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int app_list_view_top = 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) app_list->anchor_rect().y() - app_list->bounds().height() / 2; 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EXPECT_GE(app_list_view_top, kMinimalCenteredAppListMargin); 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)INSTANTIATE_TEST_CASE_P(AppListControllerTestInstance, 184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) AppListControllerTest, 185010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ::testing::Bool()); 186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace ash 188