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