1// Copyright 2014 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 "chrome/browser/ui/app_list/app_list_service_views.h"
6
7#include "base/path_service.h"
8#include "base/run_loop.h"
9#include "chrome/browser/extensions/extension_browsertest.h"
10#include "chrome/browser/lifetime/application_lifetime.h"
11#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
12#include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/browser_commands.h"
15#include "chrome/common/chrome_paths.h"
16#include "chrome/test/base/in_process_browser_test.h"
17#include "content/public/browser/notification_service.h"
18#include "content/public/test/test_utils.h"
19#include "ui/app_list/app_list_switches.h"
20#include "ui/app_list/views/app_list_view.h"
21#include "ui/events/test/event_generator.h"
22#include "ui/views/widget/widget.h"
23
24#if defined(OS_CHROMEOS)
25#include "ash/shell.h"
26#include "ash/test/app_list_controller_test_api.h"
27#endif
28
29namespace {
30
31app_list::AppListView* GetAppListView(AppListService* service) {
32#if defined(OS_CHROMEOS)
33  return ash::test::AppListControllerTestApi(ash::Shell::GetInstance()).view();
34#else
35  return static_cast<AppListServiceViews*>(service)->shower().app_list();
36#endif
37}
38
39}  // namespace
40
41namespace test {
42
43// Allow access to private variables of the AppListView for testing.
44class AppListViewTestApi {
45 public:
46  explicit AppListViewTestApi(app_list::AppListView* view) : view_(view) {}
47  virtual ~AppListViewTestApi() {}
48
49  bool is_overlay_visible() {
50    DCHECK(view_->overlay_view_);
51    return view_->overlay_view_->visible();
52  }
53
54 private:
55  app_list::AppListView* view_;
56
57  DISALLOW_COPY_AND_ASSIGN(AppListViewTestApi);
58};
59
60}  // namespace test
61
62// Browser Test for AppListService on Views platforms.
63typedef InProcessBrowserTest AppListServiceViewsBrowserTest;
64
65// Test closing the native app list window as if via a request from the OS.
66IN_PROC_BROWSER_TEST_F(AppListServiceViewsBrowserTest, NativeClose) {
67  AppListService* service = test::GetAppListService();
68  EXPECT_FALSE(service->GetAppListWindow());
69
70  // Since the profile is loaded, this will create a view immediately. This is
71  // important, because anything asynchronous would need an interactive_uitest
72  // due to the possibility of the app list being dismissed, and
73  // AppListService::GetAppListWindow returning NULL.
74  service->ShowForProfile(browser()->profile());
75  gfx::NativeWindow window = service->GetAppListWindow();
76  EXPECT_TRUE(window);
77
78  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window);
79  EXPECT_TRUE(widget);
80  widget->Close();
81
82  // Close is asynchronous (dismiss is not) so sink the message queue.
83  base::RunLoop().RunUntilIdle();
84  EXPECT_FALSE(service->GetAppListWindow());
85
86  // Show again to get some code coverage for possibly stale pointers.
87  service->ShowForProfile(browser()->profile());
88  EXPECT_TRUE(service->GetAppListWindow());
89  service->DismissAppList();  // Note: in Ash, this will invalidate the window.
90
91  // Note: no need to sink message queue.
92  EXPECT_FALSE(service->GetAppListWindow());
93}
94
95// Dismiss the app list via an accelerator when it is the only thing keeping
96// Chrome alive and expect everything to clean up properly. This is a regression
97// test for http://crbug.com/395937.
98IN_PROC_BROWSER_TEST_F(AppListServiceViewsBrowserTest, AcceleratorClose) {
99  AppListService* service = test::GetAppListService();
100  service->ShowForProfile(browser()->profile());
101  EXPECT_TRUE(service->GetAppListWindow());
102
103  content::WindowedNotificationObserver close_observer(
104      chrome::NOTIFICATION_BROWSER_CLOSED, content::Source<Browser>(browser()));
105  chrome::CloseWindow(browser());
106  close_observer.Wait();
107
108  ui::test::EventGenerator generator(service->GetAppListWindow());
109  generator.PressKey(ui::VKEY_ESCAPE, 0);
110
111#if !defined(OS_CHROMEOS)
112  EXPECT_TRUE(chrome::WillKeepAlive());
113#endif
114
115  base::RunLoop().RunUntilIdle();
116
117#if !defined(OS_CHROMEOS)
118  EXPECT_FALSE(chrome::WillKeepAlive());
119#endif
120  EXPECT_FALSE(service->GetAppListWindow());
121}
122
123// Browser Test for AppListController that ensures the App Info dialog opens
124// correctly.
125typedef ExtensionBrowserTest AppListControllerAppInfoDialogBrowserTest;
126
127// Test the DoShowAppInfoFlow function of the controller delegate.
128// flaky: http://crbug.com/378251
129IN_PROC_BROWSER_TEST_F(AppListControllerAppInfoDialogBrowserTest,
130                       DISABLED_DoShowAppInfoFlow) {
131  // Install an extension to open the dialog for.
132  base::FilePath test_extension_path;
133  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path));
134  test_extension_path = test_extension_path.AppendASCII("extensions")
135                            .AppendASCII("platform_apps")
136                            .AppendASCII("minimal");
137  const extensions::Extension* extension = InstallExtension(
138      test_extension_path, 1 /* expected_change: new install */);
139  ASSERT_TRUE(extension);
140
141  // Open the app list window.
142  AppListService* service = test::GetAppListService();
143  EXPECT_FALSE(service->GetAppListWindow());
144
145  service->ShowForProfile(browser()->profile());
146  app_list::AppListView* app_list_view = GetAppListView(service);
147  ASSERT_TRUE(app_list_view);
148  gfx::NativeView native_view = app_list_view->GetWidget()->GetNativeView();
149  ASSERT_TRUE(native_view);
150
151  test::AppListViewTestApi test_api(app_list_view);
152
153  // Open the app info dialog.
154  views::Widget::Widgets owned_widgets;
155  views::Widget::GetAllOwnedWidgets(native_view, &owned_widgets);
156  EXPECT_EQ(0U, owned_widgets.size());
157  EXPECT_FALSE(test_api.is_overlay_visible());
158
159  AppListControllerDelegate* controller = service->GetControllerDelegate();
160  ASSERT_TRUE(controller);
161  EXPECT_TRUE(controller->GetAppListWindow());
162  controller->DoShowAppInfoFlow(browser()->profile(), extension->id());
163
164  owned_widgets.clear();
165  views::Widget::GetAllOwnedWidgets(native_view, &owned_widgets);
166  EXPECT_EQ(1U, owned_widgets.size());
167  EXPECT_TRUE(test_api.is_overlay_visible());
168
169  // Close the app info dialog.
170  views::Widget* app_info_dialog = *owned_widgets.begin();
171  app_info_dialog->CloseNow();
172
173  owned_widgets.clear();
174  views::Widget::GetAllOwnedWidgets(native_view, &owned_widgets);
175  EXPECT_EQ(0U, owned_widgets.size());
176  EXPECT_FALSE(test_api.is_overlay_visible());
177}
178