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 "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
6
7 #include <stddef.h>
8 #include <memory>
9
10 #include "ash/public/cpp/app_list/app_list_features.h"
11 #include "ash/public/cpp/app_list/app_list_switches.h"
12 #include "ash/public/cpp/app_menu_constants.h"
13 #include "ash/public/cpp/ash_features.h"
14 #include "ash/public/cpp/shelf_item_delegate.h"
15 #include "ash/public/cpp/shelf_model.h"
16 #include "ash/public/cpp/shelf_test_api.h"
17 #include "ash/public/cpp/window_properties.h"
18 #include "ash/root_window_controller.h"
19 #include "ash/shelf/shelf.h"
20 #include "ash/shelf/shelf_app_button.h"
21 #include "ash/shelf/shelf_layout_manager.h"
22 #include "ash/shelf/shelf_menu_model_adapter.h"
23 #include "ash/shelf/shelf_view.h"
24 #include "ash/shelf/shelf_view_test_api.h"
25 #include "ash/shelf/shelf_widget.h"
26 #include "ash/shelf/test/widget_animation_waiter.h"
27 #include "ash/shell.h"
28 #include "ash/wm/desks/desk.h"
29 #include "ash/wm/desks/desks_controller.h"
30 #include "ash/wm/desks/desks_test_util.h"
31 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
32 #include "base/bind.h"
33 #include "base/run_loop.h"
34 #include "base/strings/stringprintf.h"
35 #include "base/strings/utf_string_conversions.h"
36 #include "base/test/bind.h"
37 #include "base/test/metrics/histogram_tester.h"
38 #include "base/test/scoped_feature_list.h"
39 #include "chrome/app/chrome_command_ids.h"
40 #include "chrome/browser/apps/app_service/app_launch_params.h"
41 #include "chrome/browser/apps/app_service/app_service_proxy.h"
42 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
43 #include "chrome/browser/apps/app_service/app_service_test.h"
44 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
45 #include "chrome/browser/apps/app_service/launch_utils.h"
46 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
47 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
48 #include "chrome/browser/chromeos/accessibility/speech_monitor.h"
49 #include "chrome/browser/chromeos/file_manager/file_manager_test_util.h"
50 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
51 #include "chrome/browser/extensions/extension_apitest.h"
52 #include "chrome/browser/extensions/extension_browsertest.h"
53 #include "chrome/browser/extensions/extension_function_test_utils.h"
54 #include "chrome/browser/extensions/extension_service.h"
55 #include "chrome/browser/extensions/launch_util.h"
56 #include "chrome/browser/extensions/menu_manager.h"
57 #include "chrome/browser/profiles/profile.h"
58 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
59 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
60 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
61 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_test_util.h"
62 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
63 #include "chrome/browser/ui/ash/launcher/shelf_context_menu.h"
64 #include "chrome/browser/ui/browser.h"
65 #include "chrome/browser/ui/browser_commands.h"
66 #include "chrome/browser/ui/browser_dialogs.h"
67 #include "chrome/browser/ui/browser_finder.h"
68 #include "chrome/browser/ui/browser_list.h"
69 #include "chrome/browser/ui/browser_window.h"
70 #include "chrome/browser/ui/chrome_pages.h"
71 #include "chrome/browser/ui/extensions/app_launch_params.h"
72 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
73 #include "chrome/browser/ui/tabs/tab_strip_model.h"
74 #include "chrome/browser/ui/test/test_app_window_icon_observer.h"
75 #include "chrome/browser/ui/views/frame/browser_view.h"
76 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
77 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
78 #include "chrome/browser/web_applications/components/app_registry_controller.h"
79 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
80 #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h"
81 #include "chrome/browser/web_applications/components/os_integration_manager.h"
82 #include "chrome/browser/web_applications/components/web_app_constants.h"
83 #include "chrome/browser/web_applications/components/web_app_helpers.h"
84 #include "chrome/browser/web_applications/components/web_app_id.h"
85 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
86 #include "chrome/browser/web_applications/components/web_application_info.h"
87 #include "chrome/browser/web_applications/system_web_app_manager.h"
88 #include "chrome/browser/web_applications/test/web_app_install_observer.h"
89 #include "chrome/browser/web_applications/web_app_provider.h"
90 #include "chrome/common/chrome_features.h"
91 #include "chrome/common/chrome_switches.h"
92 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
93 #include "chrome/common/pref_names.h"
94 #include "chrome/test/base/ui_test_utils.h"
95 #include "components/crx_file/id_util.h"
96 #include "content/public/browser/web_contents.h"
97 #include "content/public/test/browser_test.h"
98 #include "content/public/test/browser_test_utils.h"
99 #include "content/public/test/content_mock_cert_verifier.h"
100 #include "extensions/browser/app_window/app_window.h"
101 #include "extensions/browser/app_window/app_window_registry.h"
102 #include "extensions/browser/app_window/native_app_window.h"
103 #include "extensions/browser/extension_prefs.h"
104 #include "extensions/browser/extension_registry_factory.h"
105 #include "extensions/browser/extension_system.h"
106 #include "extensions/common/constants.h"
107 #include "extensions/common/switches.h"
108 #include "extensions/test/extension_test_message_listener.h"
109 #include "net/dns/mock_host_resolver.h"
110 #include "testing/gtest/include/gtest/gtest.h"
111 #include "ui/aura/client/aura_constants.h"
112 #include "ui/aura/window.h"
113 #include "ui/base/base_window.h"
114 #include "ui/base/window_open_disposition.h"
115 #include "ui/compositor/layer_animation_observer.h"
116 #include "ui/display/display.h"
117 #include "ui/display/manager/display_manager.h"
118 #include "ui/display/screen.h"
119 #include "ui/display/test/display_manager_test_api.h"
120 #include "ui/events/event.h"
121 #include "ui/events/test/event_generator.h"
122 #include "ui/events/types/event_type.h"
123 #include "ui/views/controls/menu/menu_item_view.h"
124
125 using ash::Shelf;
126 using content::WebContents;
127 using extensions::AppWindow;
128 using extensions::Extension;
129 using web_app::WebAppProviderBase;
130
131 namespace {
132
SelectItem(const ash::ShelfID & id,ui::EventType event_type=ui::ET_MOUSE_PRESSED,int64_t display_id=display::kInvalidDisplayId,ash::ShelfLaunchSource source=ash::LAUNCH_FROM_UNKNOWN)133 ash::ShelfAction SelectItem(
134 const ash::ShelfID& id,
135 ui::EventType event_type = ui::ET_MOUSE_PRESSED,
136 int64_t display_id = display::kInvalidDisplayId,
137 ash::ShelfLaunchSource source = ash::LAUNCH_FROM_UNKNOWN) {
138 return SelectShelfItem(id, event_type, display_id, source);
139 }
140
141 // Find the browser that associated with |app_name|.
FindBrowserForApp(const std::string & app_name)142 Browser* FindBrowserForApp(const std::string& app_name) {
143 for (auto* browser : *BrowserList::GetInstance()) {
144 std::string browser_app_name =
145 web_app::GetAppIdFromApplicationName(browser->app_name());
146 if (browser_app_name == app_name)
147 return browser;
148 }
149 return nullptr;
150 }
151
152 // Close |app_browser| and wait until it's closed.
CloseAppBrowserWindow(Browser * app_browser)153 void CloseAppBrowserWindow(Browser* app_browser) {
154 app_browser->window()->Close();
155 ui_test_utils::WaitForBrowserToClose(app_browser);
156 }
157
158 // Close browsers from context menu
CloseBrowserWindow(Browser * browser,ShelfContextMenu * menu,int close_command)159 void CloseBrowserWindow(Browser* browser,
160 ShelfContextMenu* menu,
161 int close_command) {
162 // Note that event_flag is never used inside function ExecuteCommand.
163 menu->ExecuteCommand(close_command, ui::EventFlags::EF_NONE);
164 ui_test_utils::WaitForBrowserToClose(browser);
165 }
166
GetDisplayIdForBrowserWindow(BrowserWindow * window)167 int64_t GetDisplayIdForBrowserWindow(BrowserWindow* window) {
168 return display::Screen::GetScreen()
169 ->GetDisplayNearestWindow(window->GetNativeWindow())
170 .id();
171 }
172
ExtendHotseat(Browser * browser)173 void ExtendHotseat(Browser* browser) {
174 ash::RootWindowController* const controller =
175 ash::Shell::GetRootWindowControllerWithDisplayId(
176 display::Screen::GetScreen()->GetPrimaryDisplay().id());
177 EXPECT_EQ(ash::HotseatState::kHidden,
178 controller->shelf()->shelf_layout_manager()->hotseat_state());
179
180 BrowserView* const browser_view =
181 BrowserView::GetBrowserViewForBrowser(browser);
182 aura::Window* const browser_window =
183 browser_view->GetWidget()->GetNativeWindow();
184
185 const gfx::Rect display_bounds = display::Screen::GetScreen()
186 ->GetDisplayNearestWindow(browser_window)
187 .bounds();
188 const gfx::Point start_point = gfx::Point(
189 display_bounds.width() / 4,
190 display_bounds.bottom() - ash::ShelfConfig::Get()->shelf_size() / 2);
191 // Swipe up for a small distance to bring up the hotseat.
192 gfx::Point end_point(start_point.x(), start_point.y() - 80);
193
194 ash::ShelfView* shelf_view = controller->shelf()->GetShelfViewForTesting();
195
196 // Observe hotseat animation before animation starts. Because
197 // ash::WidgetAnimationWaiter only reacts to completion of the animation whose
198 // animation scheduling is recorded in ash::WidgetAnimationWaiter.
199 ash::WidgetAnimationWaiter waiter(shelf_view->GetWidget());
200
201 ui::test::EventGenerator event_generator(controller->GetRootWindow());
202 event_generator.GestureScrollSequence(
203 start_point, end_point, base::TimeDelta::FromMilliseconds(500), 4);
204
205 // Wait until hotseat bounds animation completes.
206 waiter.WaitForAnimation();
207
208 EXPECT_EQ(ash::HotseatState::kExtended,
209 controller->shelf()->shelf_layout_manager()->hotseat_state());
210 }
211
212 } // namespace
213
214 class LauncherPlatformAppBrowserTest
215 : public extensions::PlatformAppBrowserTest {
216 protected:
217 LauncherPlatformAppBrowserTest() = default;
218 LauncherPlatformAppBrowserTest(const LauncherPlatformAppBrowserTest&) =
219 delete;
220 LauncherPlatformAppBrowserTest& operator=(
221 const LauncherPlatformAppBrowserTest&) = delete;
222 ~LauncherPlatformAppBrowserTest() override = default;
223
SetUpOnMainThread()224 void SetUpOnMainThread() override {
225 controller_ = ChromeLauncherController::instance();
226 ASSERT_TRUE(controller_);
227 extensions::PlatformAppBrowserTest::SetUpOnMainThread();
228 app_service_test_.SetUp(browser()->profile());
229 }
230
shelf_model()231 ash::ShelfModel* shelf_model() { return controller_->shelf_model(); }
232
CreateAppShortcutLauncherItem(const ash::ShelfID & shelf_id)233 ash::ShelfID CreateAppShortcutLauncherItem(const ash::ShelfID& shelf_id) {
234 return controller_->CreateAppShortcutLauncherItem(
235 shelf_id, shelf_model()->item_count());
236 }
237
238 // Returns the last item in the shelf.
GetLastLauncherItem()239 const ash::ShelfItem& GetLastLauncherItem() {
240 return shelf_model()->items()[shelf_model()->item_count() - 1];
241 }
242
GetShelfItemDelegate(const ash::ShelfID & id)243 ash::ShelfItemDelegate* GetShelfItemDelegate(const ash::ShelfID& id) {
244 return shelf_model()->GetShelfItemDelegate(id);
245 }
246
app_service_test()247 apps::AppServiceTest& app_service_test() { return app_service_test_; }
248
249 ChromeLauncherController* controller_ = nullptr;
250
251 private:
252 apps::AppServiceTest app_service_test_;
253 };
254
255 class ShelfAppBrowserTest : public extensions::ExtensionBrowserTest {
256 protected:
257 ShelfAppBrowserTest() = default;
258 ShelfAppBrowserTest(const ShelfAppBrowserTest&) = delete;
259 ShelfAppBrowserTest& operator=(const ShelfAppBrowserTest&) = delete;
~ShelfAppBrowserTest()260 ~ShelfAppBrowserTest() override {}
261
shelf_model() const262 ash::ShelfModel* shelf_model() const { return controller_->shelf_model(); }
263
SetUpOnMainThread()264 void SetUpOnMainThread() override {
265 controller_ = ChromeLauncherController::instance();
266 ASSERT_TRUE(controller_);
267 extensions::ExtensionBrowserTest::SetUpOnMainThread();
268 }
269
NumberOfDetectedLauncherBrowsers(bool show_all_tabs)270 size_t NumberOfDetectedLauncherBrowsers(bool show_all_tabs) {
271 ash::ShelfItemDelegate* item_controller =
272 controller_->GetBrowserShortcutLauncherItemController();
273 return item_controller
274 ->GetAppMenuItems(show_all_tabs ? ui::EF_SHIFT_DOWN : 0,
275 base::NullCallback())
276 .size();
277 }
278
LoadAndLaunchExtension(const char * name,int32_t event_flags)279 const Extension* LoadAndLaunchExtension(const char* name,
280 int32_t event_flags) {
281 EXPECT_TRUE(LoadExtension(test_data_dir_.AppendASCII(name)));
282
283 const Extension* extension = extension_registry()->GetExtensionById(
284 last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED);
285 EXPECT_TRUE(extension);
286
287 apps::AppServiceProxy* proxy =
288 apps::AppServiceProxyFactory::GetForProfile(profile());
289 proxy->FlushMojoCallsForTesting();
290 proxy->Launch(extension->id(), event_flags,
291 apps::mojom::LaunchSource::kFromTest,
292 display::Screen::GetScreen()->GetPrimaryDisplay().id());
293 proxy->FlushMojoCallsForTesting();
294 return extension;
295 }
296
CreateShortcut(const char * name)297 ash::ShelfID CreateShortcut(const char* name) {
298 LoadExtension(test_data_dir_.AppendASCII(name));
299
300 // First get app_id.
301 const Extension* extension = extension_registry()->GetExtensionById(
302 last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED);
303 const std::string app_id = extension->id();
304
305 // Then create a shortcut.
306 int item_count = shelf_model()->item_count();
307 ash::ShelfID shortcut_id = controller_->CreateAppShortcutLauncherItem(
308 ash::ShelfID(app_id), item_count);
309 controller_->SyncPinPosition(shortcut_id);
310 EXPECT_EQ(++item_count, shelf_model()->item_count());
311 const ash::ShelfItem& item = *shelf_model()->ItemByID(shortcut_id);
312 EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
313 return item.id;
314 }
315
316
317 // Get the index of an item which has the given type.
GetIndexOfShelfItemType(ash::ShelfItemType type) const318 int GetIndexOfShelfItemType(ash::ShelfItemType type) const {
319 return shelf_model()->GetItemIndexForType(type);
320 }
321
322 // Creates a context menu for the existing browser shortcut item.
CreateBrowserItemContextMenu()323 std::unique_ptr<ShelfContextMenu> CreateBrowserItemContextMenu() {
324 int index = shelf_model()->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
325 DCHECK_GE(index, 0);
326 ash::ShelfItem item = shelf_model()->items()[index];
327 int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
328 return ShelfContextMenu::Create(controller_, &item, display_id);
329 }
330
IsItemPresentInMenu(ShelfContextMenu * shelf_context_menu,int command_id)331 bool IsItemPresentInMenu(ShelfContextMenu* shelf_context_menu,
332 int command_id) {
333 base::RunLoop run_loop;
334 std::unique_ptr<ui::SimpleMenuModel> menu;
335 shelf_context_menu->GetMenuModel(base::BindLambdaForTesting(
336 [&](std::unique_ptr<ui::SimpleMenuModel> created_menu) {
337 menu = std::move(created_menu);
338 run_loop.Quit();
339 }));
340 run_loop.Run();
341 ui::MenuModel* menu_ptr = menu.get();
342 int index = 0;
343 return ui::MenuModel::GetModelAndIndexForCommandId(command_id, &menu_ptr,
344 &index);
345 }
346
347 // Flush mojo calls to allow async callbacks to run.
FlushMojoCallsForAppService()348 void FlushMojoCallsForAppService() {
349 apps::AppServiceProxy* proxy =
350 apps::AppServiceProxyFactory::GetForProfile(profile());
351 if (proxy) {
352 proxy->FlushMojoCallsForTesting();
353 }
354 }
355
356 // Launch the app and flush mojo calls to allow async callbacks to run.
LaunchAppAndFlushMojoCallsForAppService(const ash::ShelfID & id,ash::ShelfLaunchSource source,int event_flags,int64_t display_id)357 void LaunchAppAndFlushMojoCallsForAppService(const ash::ShelfID& id,
358 ash::ShelfLaunchSource source,
359 int event_flags,
360 int64_t display_id) {
361 controller_->LaunchApp(ash::ShelfID(last_loaded_extension_id()),
362 ash::LAUNCH_FROM_UNKNOWN, 0,
363 display::kInvalidDisplayId);
364 FlushMojoCallsForAppService();
365 }
366
367 // Launch and activate the app, and flush mojo calls to allow async callbacks
368 // to run.
ActivateAppAndFlushMojoCallsForAppService(const std::string & app_id,ash::ShelfLaunchSource source,int event_flags,int64_t display_id)369 void ActivateAppAndFlushMojoCallsForAppService(const std::string& app_id,
370 ash::ShelfLaunchSource source,
371 int event_flags,
372 int64_t display_id) {
373 controller_->ActivateApp(app_id, ash::LAUNCH_FROM_UNKNOWN, 0,
374 display::kInvalidDisplayId);
375 FlushMojoCallsForAppService();
376 }
377
378 // Select an item and flush mojo calls to allow async callbacks to run.
SelectItemAndFlushMojoCallsForAppService(const ash::ShelfID & id,ui::EventType event_type=ui::ET_MOUSE_PRESSED,int64_t display_id=display::kInvalidDisplayId,ash::ShelfLaunchSource source=ash::LAUNCH_FROM_UNKNOWN)379 ash::ShelfAction SelectItemAndFlushMojoCallsForAppService(
380 const ash::ShelfID& id,
381 ui::EventType event_type = ui::ET_MOUSE_PRESSED,
382 int64_t display_id = display::kInvalidDisplayId,
383 ash::ShelfLaunchSource source = ash::LAUNCH_FROM_UNKNOWN) {
384 const ash::ShelfAction action =
385 SelectItem(id, event_type, display_id, source);
386 FlushMojoCallsForAppService();
387 return action;
388 }
389
390 ChromeLauncherController* controller_ = nullptr;
391 };
392
393 class ShelfAppBrowserTestNoDefaultBrowser : public ShelfAppBrowserTest {
394 protected:
ShelfAppBrowserTestNoDefaultBrowser()395 ShelfAppBrowserTestNoDefaultBrowser() {}
396 ShelfAppBrowserTestNoDefaultBrowser(
397 const ShelfAppBrowserTestNoDefaultBrowser&) = delete;
398 ShelfAppBrowserTestNoDefaultBrowser& operator=(
399 const ShelfAppBrowserTestNoDefaultBrowser&) = delete;
~ShelfAppBrowserTestNoDefaultBrowser()400 ~ShelfAppBrowserTestNoDefaultBrowser() override {}
401
SetUpCommandLine(base::CommandLine * command_line)402 void SetUpCommandLine(base::CommandLine* command_line) override {
403 ShelfAppBrowserTest::SetUpCommandLine(command_line);
404 command_line->AppendSwitch(switches::kNoStartupWindow);
405 }
406 };
407
408 class ShelfWebAppBrowserTest : public ShelfAppBrowserTest {
409 protected:
ShelfWebAppBrowserTest()410 ShelfWebAppBrowserTest()
411 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
412 }
413
414 ~ShelfWebAppBrowserTest() override = default;
415
https_server()416 net::EmbeddedTestServer* https_server() { return &https_server_; }
417
GetSecureAppURL()418 GURL GetSecureAppURL() {
419 return https_server()->GetURL("app.com", "/ssl/google.html");
420 }
421
InstallWebApp(const GURL & start_url)422 web_app::AppId InstallWebApp(const GURL& start_url) {
423 auto web_app_info = std::make_unique<WebApplicationInfo>();
424 web_app_info->start_url = start_url;
425 web_app_info->scope = start_url.GetWithoutFilename();
426 return web_app::InstallWebApp(browser()->profile(),
427 std::move(web_app_info));
428 }
429
430 // ShelfAppBrowserTest:
SetUp()431 void SetUp() override {
432 https_server_.AddDefaultHandlers(GetChromeTestDataDir());
433 ShelfAppBrowserTest::SetUp();
434 }
SetUpInProcessBrowserTestFixture()435 void SetUpInProcessBrowserTestFixture() override {
436 ShelfAppBrowserTest::SetUpInProcessBrowserTestFixture();
437 cert_verifier_.SetUpInProcessBrowserTestFixture();
438 }
TearDownInProcessBrowserTestFixture()439 void TearDownInProcessBrowserTestFixture() override {
440 ShelfAppBrowserTest::TearDownInProcessBrowserTestFixture();
441 cert_verifier_.TearDownInProcessBrowserTestFixture();
442 }
SetUpCommandLine(base::CommandLine * command_line)443 void SetUpCommandLine(base::CommandLine* command_line) override {
444 ShelfAppBrowserTest::SetUpCommandLine(command_line);
445 cert_verifier_.SetUpCommandLine(command_line);
446 }
SetUpOnMainThread()447 void SetUpOnMainThread() override {
448 ShelfAppBrowserTest::SetUpOnMainThread();
449 host_resolver()->AddRule("*", "127.0.0.1");
450 ASSERT_TRUE(https_server()->Start());
451 cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
452
453 os_hooks_suppress_ =
454 web_app::OsIntegrationManager::ScopedSuppressOsHooksForTesting();
455 }
456
457 private:
458 net::EmbeddedTestServer https_server_;
459 content::ContentMockCertVerifier cert_verifier_;
460 web_app::ScopedOsHooksSuppress os_hooks_suppress_;
461 };
462
463 // Test that we can launch a platform app and get a running item.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,LaunchUnpinned)464 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchUnpinned) {
465 int item_count = shelf_model()->item_count();
466 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
467 AppWindow* window = CreateAppWindow(browser()->profile(), extension);
468 ++item_count;
469 ASSERT_EQ(item_count, shelf_model()->item_count());
470 const ash::ShelfItem& item = GetLastLauncherItem();
471 EXPECT_EQ(ash::TYPE_APP, item.type);
472 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
473 CloseAppWindow(window);
474 --item_count;
475 EXPECT_EQ(item_count, shelf_model()->item_count());
476 }
477
478 // Test that we can launch a platform app that already has a shortcut.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,LaunchPinned)479 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchPinned) {
480 int item_count = shelf_model()->item_count();
481
482 // First get app_id.
483 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
484 const std::string app_id = extension->id();
485
486 // Then create a shortcut.
487 ash::ShelfID shortcut_id =
488 CreateAppShortcutLauncherItem(ash::ShelfID(app_id));
489 ++item_count;
490 ASSERT_EQ(item_count, shelf_model()->item_count());
491 ash::ShelfItem item = *shelf_model()->ItemByID(shortcut_id);
492 EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
493 EXPECT_EQ(ash::STATUS_CLOSED, item.status);
494
495 // Open a window. Confirm the item is now running.
496 AppWindow* window = CreateAppWindow(browser()->profile(), extension);
497 window->GetBaseWindow()->Activate();
498 ASSERT_EQ(item_count, shelf_model()->item_count());
499 item = *shelf_model()->ItemByID(shortcut_id);
500 EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
501 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
502
503 // Then close it, make sure there's still an item.
504 CloseAppWindow(window);
505 ASSERT_EQ(item_count, shelf_model()->item_count());
506 item = *shelf_model()->ItemByID(shortcut_id);
507 EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
508 EXPECT_EQ(ash::STATUS_CLOSED, item.status);
509 }
510
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,PinRunning)511 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, PinRunning) {
512 // Run.
513 int item_count = shelf_model()->item_count();
514 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
515 AppWindow* window = CreateAppWindow(browser()->profile(), extension);
516 ++item_count;
517 ASSERT_EQ(item_count, shelf_model()->item_count());
518 const ash::ShelfItem& item1 = GetLastLauncherItem();
519 ash::ShelfID id = item1.id;
520 EXPECT_EQ(ash::TYPE_APP, item1.type);
521 EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
522
523 // Create a shortcut. The app item should be after it.
524 ash::ShelfID foo_id = CreateAppShortcutLauncherItem(
525 ash::ShelfID(extension_misc::kYoutubeAppId));
526 ++item_count;
527 ASSERT_EQ(item_count, shelf_model()->item_count());
528 EXPECT_LT(shelf_model()->ItemIndexByID(foo_id),
529 shelf_model()->ItemIndexByID(id));
530
531 // Pin the app. The item should remain.
532 controller_->PinAppWithID(extension->id());
533 ASSERT_EQ(item_count, shelf_model()->item_count());
534 const ash::ShelfItem& item2 = *shelf_model()->ItemByID(id);
535 EXPECT_EQ(ash::TYPE_PINNED_APP, item2.type);
536 EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
537
538 // New shortcuts should come after the item.
539 ash::ShelfID bar_id = CreateAppShortcutLauncherItem(
540 ash::ShelfID(extension_misc::kGoogleDocAppId));
541 ++item_count;
542 ASSERT_EQ(item_count, shelf_model()->item_count());
543 EXPECT_LT(shelf_model()->ItemIndexByID(id),
544 shelf_model()->ItemIndexByID(bar_id));
545
546 // Then close it, make sure the item remains.
547 CloseAppWindow(window);
548 ASSERT_EQ(item_count, shelf_model()->item_count());
549 }
550
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,UnpinRunning)551 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, UnpinRunning) {
552 int item_count = shelf_model()->item_count();
553
554 // First get app_id.
555 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
556 const std::string app_id = extension->id();
557
558 // Then create a shortcut.
559 ash::ShelfID shortcut_id =
560 CreateAppShortcutLauncherItem(ash::ShelfID(app_id));
561 ++item_count;
562 ASSERT_EQ(item_count, shelf_model()->item_count());
563 ash::ShelfItem item = *shelf_model()->ItemByID(shortcut_id);
564 EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
565 EXPECT_EQ(ash::STATUS_CLOSED, item.status);
566
567 // Create a second shortcut. This will be needed to force the first one to
568 // move once it gets unpinned.
569 ash::ShelfID foo_id = CreateAppShortcutLauncherItem(
570 ash::ShelfID(extension_misc::kYoutubeAppId));
571 ++item_count;
572 ASSERT_EQ(item_count, shelf_model()->item_count());
573 EXPECT_LT(shelf_model()->ItemIndexByID(shortcut_id),
574 shelf_model()->ItemIndexByID(foo_id));
575
576 // Open a window. Confirm the item is now running.
577 AppWindow* window = CreateAppWindow(browser()->profile(), extension);
578 window->GetBaseWindow()->Activate();
579 ASSERT_EQ(item_count, shelf_model()->item_count());
580 item = *shelf_model()->ItemByID(shortcut_id);
581 EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
582 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
583
584 // Unpin the app. The item should remain.
585 controller_->UnpinAppWithID(app_id);
586 ASSERT_EQ(item_count, shelf_model()->item_count());
587 item = *shelf_model()->ItemByID(shortcut_id);
588 EXPECT_EQ(ash::TYPE_APP, item.type);
589 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
590 // The item should have moved after the other shortcuts.
591 EXPECT_GT(shelf_model()->ItemIndexByID(shortcut_id),
592 shelf_model()->ItemIndexByID(foo_id));
593
594 // Then close it, make sure the item's gone.
595 CloseAppWindow(window);
596 --item_count;
597 ASSERT_EQ(item_count, shelf_model()->item_count());
598 }
599
600 // Test that we can launch a platform app with more than one window.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,MultipleWindows)601 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MultipleWindows) {
602 int item_count = shelf_model()->item_count();
603
604 // Run the application; a shelf item should be added with one app menu item.
605 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
606 AppWindow* window1 = CreateAppWindow(browser()->profile(), extension);
607 ASSERT_EQ(item_count + 1, shelf_model()->item_count());
608 const ash::ShelfItem& item1 = GetLastLauncherItem();
609 ash::ShelfID item_id = item1.id;
610 EXPECT_EQ(ash::TYPE_APP, item1.type);
611 EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
612 EXPECT_EQ(1u, controller_->GetAppMenuItemsForTesting(item1).size());
613
614 // Add a second window; confirm the shelf item stays; check the app menu.
615 AppWindow* window2 = CreateAppWindow(browser()->profile(), extension);
616 ASSERT_EQ(item_count + 1, shelf_model()->item_count());
617 const ash::ShelfItem& item2 = *shelf_model()->ItemByID(item_id);
618 EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
619 EXPECT_EQ(2u, controller_->GetAppMenuItemsForTesting(item2).size());
620
621 // Close the second window; confirm the shelf item stays; check the app menu.
622 CloseAppWindow(window2);
623 ASSERT_EQ(item_count + 1, shelf_model()->item_count());
624 const ash::ShelfItem& item3 = *shelf_model()->ItemByID(item_id);
625 EXPECT_EQ(ash::STATUS_RUNNING, item3.status);
626 EXPECT_EQ(1u, controller_->GetAppMenuItemsForTesting(item3).size());
627
628 // Close the first window; the shelf item should be removed.
629 CloseAppWindow(window1);
630 ASSERT_EQ(item_count, shelf_model()->item_count());
631 }
632
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,MultipleApps)633 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MultipleApps) {
634 int item_count = shelf_model()->item_count();
635
636 // First run app.
637 const Extension* extension1 = LoadAndLaunchPlatformApp("launch", "Launched");
638 AppWindow* window1 = CreateAppWindow(browser()->profile(), extension1);
639 ++item_count;
640 ASSERT_EQ(item_count, shelf_model()->item_count());
641 const ash::ShelfItem& item1 = GetLastLauncherItem();
642 ash::ShelfID item_id1 = item1.id;
643 EXPECT_EQ(ash::TYPE_APP, item1.type);
644 EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
645
646 // Then run second app.
647 const Extension* extension2 =
648 LoadAndLaunchPlatformApp("launch_2", "Launched");
649 AppWindow* window2 = CreateAppWindow(browser()->profile(), extension2);
650 ++item_count;
651 ASSERT_EQ(item_count, shelf_model()->item_count());
652 const ash::ShelfItem& item2 = GetLastLauncherItem();
653 ash::ShelfID item_id2 = item2.id;
654 EXPECT_EQ(ash::TYPE_APP, item2.type);
655 EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
656
657 EXPECT_NE(item_id1, item_id2);
658 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
659
660 // Close second app.
661 CloseAppWindow(window2);
662 --item_count;
663 ASSERT_EQ(item_count, shelf_model()->item_count());
664 // First app should still be running.
665 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
666
667 // Close first app.
668 CloseAppWindow(window1);
669 --item_count;
670 ASSERT_EQ(item_count, shelf_model()->item_count());
671 }
672
673 // Confirm that app windows can be reactivated by clicking their icons and that
674 // the correct activation order is maintained.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,WindowActivation)675 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, WindowActivation) {
676 int item_count = shelf_model()->item_count();
677
678 // First run app.
679 const Extension* extension1 = LoadAndLaunchPlatformApp("launch", "Launched");
680 AppWindow* window1 = CreateAppWindow(browser()->profile(), extension1);
681 ++item_count;
682 ASSERT_EQ(item_count, shelf_model()->item_count());
683 const ash::ShelfItem& item1 = GetLastLauncherItem();
684 ash::ShelfID item_id1 = item1.id;
685 EXPECT_EQ(ash::TYPE_APP, item1.type);
686 EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
687
688 // Then run second app.
689 const Extension* extension2 =
690 LoadAndLaunchPlatformApp("launch_2", "Launched");
691 AppWindow* window2 = CreateAppWindow(browser()->profile(), extension2);
692 ++item_count;
693 ASSERT_EQ(item_count, shelf_model()->item_count());
694 const ash::ShelfItem& item2 = GetLastLauncherItem();
695 ash::ShelfID item_id2 = item2.id;
696 EXPECT_EQ(ash::TYPE_APP, item2.type);
697 EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
698
699 EXPECT_NE(item_id1, item_id2);
700 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
701
702 // Activate first one.
703 SelectItem(item_id1);
704 EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
705 EXPECT_FALSE(window2->GetBaseWindow()->IsActive());
706
707 // Activate second one.
708 SelectItem(item_id2);
709 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
710 EXPECT_TRUE(window2->GetBaseWindow()->IsActive());
711
712 // Add window for app1. This will activate it.
713 AppWindow* window1b = CreateAppWindow(browser()->profile(), extension1);
714 window1b->GetBaseWindow()->Activate();
715 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
716 EXPECT_FALSE(window2->GetBaseWindow()->IsActive());
717 EXPECT_TRUE(window1b->GetBaseWindow()->IsActive());
718
719 // Key events selecting app1's shelf item will cycle through its windows.
720 SelectItem(item_id1, ui::ET_KEY_RELEASED);
721 EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
722 EXPECT_FALSE(window1b->GetBaseWindow()->IsActive());
723 SelectItem(item_id1, ui::ET_KEY_RELEASED);
724 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
725 EXPECT_TRUE(window1b->GetBaseWindow()->IsActive());
726
727 // Activate the second app again
728 SelectItem(item_id2);
729 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
730 EXPECT_TRUE(window2->GetBaseWindow()->IsActive());
731 EXPECT_FALSE(window1b->GetBaseWindow()->IsActive());
732
733 // Activate the first app again
734 SelectItem(item_id1);
735 EXPECT_TRUE(window1b->GetBaseWindow()->IsActive());
736 EXPECT_FALSE(window2->GetBaseWindow()->IsActive());
737 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
738
739 // Close second app.
740 CloseAppWindow(window2);
741 --item_count;
742 EXPECT_EQ(item_count, shelf_model()->item_count());
743 // First app is still running.
744 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
745
746 // Close first app.
747 CloseAppWindow(window1b);
748 CloseAppWindow(window1);
749 --item_count;
750 EXPECT_EQ(item_count, shelf_model()->item_count());
751 }
752
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,MultipleBrowsers)753 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MultipleBrowsers) {
754 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
755 Browser* const browser1 = chrome::FindLastActive();
756 ASSERT_TRUE(browser1);
757
758 Browser* const browser2 = CreateBrowser(profile());
759 ASSERT_TRUE(browser2);
760 EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
761 EXPECT_NE(browser1->window(), browser2->window());
762 EXPECT_TRUE(browser2->window()->IsActive());
763
764 const Extension* app = LoadAndLaunchPlatformApp("launch", "Launched");
765 ui::BaseWindow* const app_window =
766 CreateAppWindow(browser()->profile(), app)->GetBaseWindow();
767
768 const ash::ShelfItem item = GetLastLauncherItem();
769 EXPECT_EQ(app->id(), item.id.app_id);
770 EXPECT_EQ(ash::TYPE_APP, item.type);
771 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
772
773 EXPECT_TRUE(app_window->IsActive());
774 EXPECT_FALSE(browser2->window()->IsActive());
775
776 controller_->ActivateApp(extension_misc::kChromeAppId,
777 ash::LAUNCH_FROM_APP_LIST, 0,
778 display::kInvalidDisplayId);
779
780 EXPECT_FALSE(app_window->IsActive());
781 EXPECT_TRUE(browser2->window()->IsActive());
782 }
783
784 // Confirm the minimizing click behavior for apps.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,PackagedAppClickBehaviorInMinimizeMode)785 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,
786 PackagedAppClickBehaviorInMinimizeMode) {
787 // Launch one platform app and create a window for it.
788 const Extension* extension1 = LoadAndLaunchPlatformApp("launch", "Launched");
789 AppWindow* window1 = CreateAppWindow(browser()->profile(), extension1);
790 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
791 EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
792
793 // Confirm that a controller item was created and is the correct state.
794 const ash::ShelfItem& item = GetLastLauncherItem();
795 EXPECT_EQ(ash::TYPE_APP, item.type);
796 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
797 // Since it is already active, clicking it should minimize.
798 SelectItem(item.id);
799 EXPECT_FALSE(window1->GetNativeWindow()->IsVisible());
800 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
801 EXPECT_TRUE(window1->GetBaseWindow()->IsMinimized());
802 // Clicking the item again should activate the window again.
803 SelectItem(item.id);
804 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
805 EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
806 // Maximizing a window should preserve state after minimize + click.
807 window1->GetBaseWindow()->Maximize();
808 window1->GetBaseWindow()->Minimize();
809 SelectItem(item.id);
810 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
811 EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
812 EXPECT_TRUE(window1->GetBaseWindow()->IsMaximized());
813 window1->GetBaseWindow()->Restore();
814 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
815 EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
816 EXPECT_FALSE(window1->GetBaseWindow()->IsMaximized());
817
818 // Creating a second window of the same type should change the behavior so
819 // that a click on the shelf item does not change the activation state.
820 AppWindow* window1a = CreateAppWindow(browser()->profile(), extension1);
821 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
822 EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
823 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
824 EXPECT_TRUE(window1a->GetBaseWindow()->IsActive());
825
826 // Ensure the same shelf item and delegate are used for |window1a|.
827 EXPECT_EQ(item.id, GetLastLauncherItem().id);
828 EXPECT_EQ(GetShelfItemDelegate(item.id),
829 GetShelfItemDelegate(GetLastLauncherItem().id));
830
831 // The first click does nothing.
832 SelectItem(item.id);
833 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
834 EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
835 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
836 EXPECT_TRUE(window1a->GetBaseWindow()->IsActive());
837 // The second neither.
838 SelectItem(item.id);
839 EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
840 EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
841 EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
842 EXPECT_TRUE(window1a->GetBaseWindow()->IsActive());
843 }
844
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,BrowserActivation)845 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, BrowserActivation) {
846 int item_count = shelf_model()->item_count();
847
848 // First run app.
849 const Extension* extension1 = LoadAndLaunchPlatformApp("launch", "Launched");
850 CreateAppWindow(browser()->profile(), extension1);
851 ++item_count;
852 ASSERT_EQ(item_count, shelf_model()->item_count());
853 const ash::ShelfItem& item = GetLastLauncherItem();
854 ash::ShelfID item_id1 = item.id;
855 EXPECT_EQ(ash::TYPE_APP, item.type);
856 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
857
858 browser()->window()->Activate();
859 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
860 }
861
862 // Test that opening an app sets the correct icon
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,SetIcon)863 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, SetIcon) {
864 TestAppWindowIconObserver test_observer(browser()->profile());
865
866 int base_shelf_item_count = shelf_model()->item_count();
867 ExtensionTestMessageListener ready_listener("ready", true);
868 const Extension* extension = LoadAndLaunchPlatformApp("app_icon", "Launched");
869 ASSERT_TRUE(extension);
870
871 gfx::ImageSkia image_skia;
872 if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
873 // Only when the kAppServiceAdaptiveIcon feature is enabled, AppService is
874 // called to load icons for windows. So the image checking is available when
875 // the kAppServiceAdaptiveIcon feature is enabled.
876 int32_t size_hint_in_dip = 48;
877 image_skia = app_service_test().LoadAppIconBlocking(
878 apps::mojom::AppType::kExtension, extension->id(), size_hint_in_dip);
879 }
880
881 // Create non-shelf window.
882 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
883 ready_listener.Reply("createNonShelfWindow");
884 ready_listener.Reset();
885 if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
886 // Default app icon + extension icon updates + AppServiceProxy load icon
887 // updates.
888 test_observer.WaitForIconUpdates(3);
889 EXPECT_TRUE(app_service_test().AreIconImageEqual(
890 image_skia, test_observer.last_app_icon()));
891 } else {
892 // Default app icon + extension icon updates.
893 test_observer.WaitForIconUpdates(2);
894 }
895
896 // Create shelf window.
897 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
898 ready_listener.Reply("createShelfWindow");
899 ready_listener.Reset();
900 if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
901 // Default app icon + extension icon updates + AppServiceProxy load icon
902 // updates.
903 test_observer.WaitForIconUpdates(3);
904 EXPECT_TRUE(app_service_test().AreIconImageEqual(
905 image_skia, test_observer.last_app_icon()));
906 } else {
907 // Default app icon + extension icon updates.
908 test_observer.WaitForIconUpdates(2);
909 }
910
911 // Set shelf window icon.
912 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
913 ready_listener.Reply("setShelfWindowIcon");
914 ready_listener.Reset();
915 // Custom icon update.
916 test_observer.WaitForIconUpdate();
917 if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
918 EXPECT_FALSE(app_service_test().AreIconImageEqual(
919 image_skia, test_observer.last_app_icon()));
920 }
921 gfx::ImageSkia custome_icon = test_observer.last_app_icon();
922
923 // Create shelf window with custom icon on init.
924 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
925 ready_listener.Reply("createShelfWindowWithCustomIcon");
926 ready_listener.Reset();
927 int update_number;
928 if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
929 // Default app icon + extension icon + AppServiceProxy load icon + custom
930 // icon updates. Ensure the custom icon is set as the window's icon.
931 test_observer.WaitForIconUpdates(custome_icon);
932 EXPECT_TRUE(app_service_test().AreIconImageEqual(
933 custome_icon, test_observer.last_app_icon()));
934 update_number = test_observer.icon_updates();
935 } else {
936 // Default app icon + extension icon + custom icon updates.
937 test_observer.WaitForIconUpdates(3);
938 update_number = test_observer.icon_updates();
939 }
940
941 const gfx::ImageSkia app_item_custom_image = test_observer.last_app_icon();
942
943 const int shelf_item_count = shelf_model()->item_count();
944 ASSERT_EQ(base_shelf_item_count + 3, shelf_item_count);
945
946 const ash::ShelfItem& app_item =
947 shelf_model()->items()[base_shelf_item_count];
948 const ash::ShelfItem& app_custom_icon_item =
949 shelf_model()->items()[base_shelf_item_count + 1];
950
951 // Icons for Apps are set by the AppWindowLauncherController, so
952 // image_set_by_controller() should be set.
953 const ash::ShelfItemDelegate* app_item_delegate =
954 GetShelfItemDelegate(app_item.id);
955 ASSERT_TRUE(app_item_delegate);
956 EXPECT_TRUE(app_item_delegate->image_set_by_controller());
957
958 const ash::ShelfItemDelegate* app_custom_icon_item_delegate =
959 GetShelfItemDelegate(app_custom_icon_item.id);
960 ASSERT_TRUE(app_custom_icon_item_delegate);
961 EXPECT_TRUE(app_custom_icon_item_delegate->image_set_by_controller());
962
963 // Ensure icon height is correct (see test.js in app_icon/ test directory)
964 // Note, images are no longer available in ChromeLauncherController. They are
965 // are passed directly to the ShelfController.
966 EXPECT_EQ(extension_misc::EXTENSION_ICON_LARGE,
967 app_item_custom_image.height());
968
969 // No more icon updates.
970 base::RunLoop().RunUntilIdle();
971 EXPECT_TRUE(app_service_test().AreIconImageEqual(
972 custome_icon, test_observer.last_app_icon()));
973 EXPECT_EQ(update_number, test_observer.icon_updates());
974
975 // Exit.
976 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
977 ready_listener.Reply("exit");
978 ready_listener.Reset();
979 }
980
981 // Test that app window has shelf ID and app ID properties set.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,AppIDWindowProperties)982 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, AppIDWindowProperties) {
983 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
984 AppWindow* window = CreateAppWindow(browser()->profile(), extension);
985 ASSERT_TRUE(window);
986
987 const gfx::NativeWindow native_window = window->GetNativeWindow();
988 ash::ShelfID shelf_id =
989 ash::ShelfID::Deserialize(native_window->GetProperty(ash::kShelfIDKey));
990 EXPECT_EQ(extension->id(), shelf_id.app_id);
991 std::string* app_id = native_window->GetProperty(ash::kAppIDKey);
992 ASSERT_TRUE(app_id);
993 EXPECT_EQ(shelf_id.app_id, *app_id);
994
995 CloseAppWindow(window);
996 }
997
998 // Test that we can launch an app with a shortcut.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchPinned)999 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchPinned) {
1000 TabStripModel* tab_strip = browser()->tab_strip_model();
1001 int tab_count = tab_strip->count();
1002 ash::ShelfID shortcut_id = CreateShortcut("app1");
1003 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1004 SelectItemAndFlushMojoCallsForAppService(shortcut_id);
1005 EXPECT_EQ(++tab_count, tab_strip->count());
1006 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1007 WebContents* tab = tab_strip->GetActiveWebContents();
1008 content::WebContentsDestroyedWatcher destroyed_watcher(tab);
1009 browser()->tab_strip_model()->CloseSelectedTabs();
1010 destroyed_watcher.Wait();
1011 EXPECT_EQ(--tab_count, tab_strip->count());
1012 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1013 }
1014
1015 // Tests behavior of launching app from shelf in the first display while the
1016 // second display has the focus. Initially, Browsers exists in the first
1017 // display.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchAppFromDisplayWithoutFocus0)1018 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchAppFromDisplayWithoutFocus0) {
1019 // Updates the display configuration to add a secondary display.
1020 display::DisplayManager* display_manager =
1021 ash::Shell::Get()->display_manager();
1022 display::test::DisplayManagerTestApi(display_manager)
1023 .UpdateDisplay("0+0-800x800,801+0-800x800");
1024 display::Displays displays = display_manager->active_display_list();
1025 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1026 EXPECT_EQ(displays.size(), 2U);
1027 EXPECT_EQ(roots.size(), 2U);
1028 EXPECT_EQ(
1029 displays[0].id(),
1030 display::Screen::GetScreen()->GetDisplayNearestWindow(roots[0]).id());
1031 EXPECT_EQ(
1032 displays[1].id(),
1033 display::Screen::GetScreen()->GetDisplayNearestWindow(roots[1]).id());
1034
1035 // Ensures that display 0 has one browser with focus and display 1 has two
1036 // browsers. Each browser only has one tab.
1037 BrowserList* browser_list = BrowserList::GetInstance();
1038 Browser* browser0 = browser();
1039 Browser* browser1 = CreateBrowser(browser()->profile());
1040 Browser* browser2 = CreateBrowser(browser()->profile());
1041 browser0->window()->SetBounds(displays[0].work_area());
1042 browser1->window()->SetBounds(displays[1].work_area());
1043 browser2->window()->SetBounds(displays[1].work_area());
1044 // Ensures browser 2 is above browser 1 in display 1.
1045 browser_list->SetLastActive(browser2);
1046 browser_list->SetLastActive(browser0);
1047 EXPECT_EQ(browser_list->size(), 3U);
1048 EXPECT_EQ(displays[0].id(), GetDisplayIdForBrowserWindow(browser0->window()));
1049 EXPECT_EQ(displays[1].id(), GetDisplayIdForBrowserWindow(browser1->window()));
1050 EXPECT_EQ(displays[1].id(), GetDisplayIdForBrowserWindow(browser2->window()));
1051 EXPECT_EQ(browser0->tab_strip_model()->count(), 1);
1052 EXPECT_EQ(browser1->tab_strip_model()->count(), 1);
1053 EXPECT_EQ(browser2->tab_strip_model()->count(), 1);
1054
1055 // Launches an app from the shelf of display 0 and expects a new tab is opened
1056 // in the uppermost browser in display 0.
1057 ash::ShelfID shortcut_id = CreateShortcut("app1");
1058 SelectItemAndFlushMojoCallsForAppService(shortcut_id, ui::ET_MOUSE_PRESSED,
1059 displays[1].id());
1060 EXPECT_EQ(browser0->tab_strip_model()->count(), 1);
1061 EXPECT_EQ(browser1->tab_strip_model()->count(), 1);
1062 EXPECT_EQ(browser2->tab_strip_model()->count(), 2);
1063 }
1064
1065 // Tests behavior of launching app from shelf in the first display while the
1066 // second display has the focus. Initially, No browser exists in the first
1067 // display.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchAppFromDisplayWithoutFocus1)1068 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchAppFromDisplayWithoutFocus1) {
1069 // Updates the display configuration to add a secondary display.
1070 display::DisplayManager* display_manager =
1071 ash::Shell::Get()->display_manager();
1072 display::test::DisplayManagerTestApi(display_manager)
1073 .UpdateDisplay("800x800,801+0-800x800");
1074 display::Displays displays = display_manager->active_display_list();
1075 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1076 EXPECT_EQ(displays.size(), 2U);
1077 EXPECT_EQ(roots.size(), 2U);
1078 EXPECT_EQ(
1079 displays[0].id(),
1080 display::Screen::GetScreen()->GetDisplayNearestWindow(roots[0]).id());
1081 EXPECT_EQ(
1082 displays[1].id(),
1083 display::Screen::GetScreen()->GetDisplayNearestWindow(roots[1]).id());
1084
1085 // Ensures that display 0 has one browser with focus and display 1 has no
1086 // browser. The browser only has one tab.
1087 BrowserList* browser_list = BrowserList::GetInstance();
1088 Browser* browser0 = browser();
1089 browser0->window()->SetBounds(displays[0].work_area());
1090 EXPECT_EQ(browser_list->size(), 1U);
1091 EXPECT_EQ(displays[0].id(), GetDisplayIdForBrowserWindow(browser0->window()));
1092 EXPECT_EQ(browser0->tab_strip_model()->count(), 1);
1093
1094 // Launches an app from the shelf of display 0 and expects a new browser with
1095 // one tab is opened in display 0.
1096 ash::ShelfID shortcut_id = CreateShortcut("app1");
1097 SelectItemAndFlushMojoCallsForAppService(shortcut_id, ui::ET_MOUSE_PRESSED,
1098 displays[1].id());
1099 Browser* browser1 = browser_list->GetLastActive();
1100 EXPECT_EQ(browser_list->size(), 2U);
1101 EXPECT_NE(browser1, browser0);
1102 EXPECT_EQ(browser0->tab_strip_model()->count(), 1);
1103 EXPECT_EQ(browser1->tab_strip_model()->count(), 1);
1104 }
1105
1106 // Launch the app first and then create the shortcut.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchUnpinned)1107 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchUnpinned) {
1108 TabStripModel* tab_strip = browser()->tab_strip_model();
1109 int tab_count = tab_strip->count();
1110 LoadAndLaunchExtension(
1111 "app1",
1112 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
1113 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1114 true /* prefer_containner */));
1115 EXPECT_EQ(++tab_count, tab_strip->count());
1116 ash::ShelfID shortcut_id = CreateShortcut("app1");
1117 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1118 WebContents* tab = tab_strip->GetActiveWebContents();
1119 content::WebContentsDestroyedWatcher destroyed_watcher(tab);
1120 browser()->tab_strip_model()->CloseSelectedTabs();
1121 destroyed_watcher.Wait();
1122 EXPECT_EQ(--tab_count, tab_strip->count());
1123 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1124 }
1125
1126 // Verifies that native browser window properties are properly set when showing
1127 // an unpinned hosted app web contents.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,AppIDForUnpinnedHostedApp)1128 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AppIDForUnpinnedHostedApp) {
1129 const extensions::Extension* extension = LoadAndLaunchExtension(
1130 "app1",
1131 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
1132 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1133 true /* prefer_containner */));
1134
1135 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
1136 ash::ShelfID browser_id = shelf_model()->items()[browser_index].id;
1137
1138 // If the app is not pinned, and thus does not have an associated shelf item,
1139 // the shelf ID should be set to the browser ID,
1140 const gfx::NativeWindow native_window =
1141 browser()->window()->GetNativeWindow();
1142 ash::ShelfID shelf_id =
1143 ash::ShelfID::Deserialize(native_window->GetProperty(ash::kShelfIDKey));
1144 EXPECT_EQ(browser_id, shelf_id);
1145 // The app ID should have the actual extension ID.
1146 std::string* app_id = native_window->GetProperty(ash::kAppIDKey);
1147 ASSERT_TRUE(app_id);
1148 EXPECT_EQ(extension->id(), *app_id);
1149 }
1150
1151 // Verifies that native browser window properties are properly set when showing
1152 // a pinned hosted app web contents.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,AppIDForPinnedHostedApp)1153 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AppIDForPinnedHostedApp) {
1154 // Load and pin a hosted app.
1155 const Extension* extension =
1156 LoadExtension(test_data_dir_.AppendASCII("app1/"));
1157 ASSERT_TRUE(extension);
1158 controller_->PinAppWithID(extension->id());
1159
1160 // Navigate to the app's launch URL.
1161 ui_test_utils::NavigateToURL(
1162 browser(), extensions::AppLaunchInfo::GetLaunchWebURL(extension));
1163
1164 // When an app shportcut exists, the window shelf ID should point to the app
1165 // shortcut.
1166 const gfx::NativeWindow native_window =
1167 browser()->window()->GetNativeWindow();
1168 ash::ShelfID shelf_id =
1169 ash::ShelfID::Deserialize(native_window->GetProperty(ash::kShelfIDKey));
1170 EXPECT_EQ(extension->id(), shelf_id.app_id);
1171 std::string* app_id = native_window->GetProperty(ash::kAppIDKey);
1172 ASSERT_TRUE(app_id);
1173 EXPECT_EQ(extension->id(), *app_id);
1174 }
1175
1176 // Verifies that native browser window properties are properly set when showing
1177 // an unpinned web app.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,AppIDForUnpinnedWebApp)1178 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, AppIDForUnpinnedWebApp) {
1179 // Load and navigate to a web app.
1180 const GURL app_url = GetSecureAppURL();
1181 const web_app::AppId web_app_id = InstallWebApp(app_url);
1182
1183 ui_test_utils::NavigateToURL(browser(), app_url);
1184
1185 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
1186 ash::ShelfID browser_id = shelf_model()->items()[browser_index].id;
1187
1188 // If the app is not pinned, and thus does not have an associated shelf item,
1189 // the shelf ID should be set to the browser ID,
1190 const gfx::NativeWindow native_window =
1191 browser()->window()->GetNativeWindow();
1192 ash::ShelfID shelf_id =
1193 ash::ShelfID::Deserialize(native_window->GetProperty(ash::kShelfIDKey));
1194 EXPECT_EQ(browser_id, shelf_id);
1195 // The app ID should have the actual web app ID.
1196 std::string* app_id = native_window->GetProperty(ash::kAppIDKey);
1197 ASSERT_TRUE(app_id);
1198 EXPECT_EQ(web_app_id, *app_id);
1199 }
1200
1201 // Verifies that native browser window properties are properly set when showing
1202 // a pinned web app.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,AppIDForPinnedWebApp)1203 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, AppIDForPinnedWebApp) {
1204 // Load and navigate to a web app.
1205 const GURL app_url = GetSecureAppURL();
1206 const web_app::AppId web_app_id = InstallWebApp(app_url);
1207
1208 controller_->PinAppWithID(web_app_id);
1209
1210 // Navigate to the app's launch URL.
1211 ui_test_utils::NavigateToURL(browser(), app_url);
1212
1213 // When an app shportcut exists, the window shelf ID should point to the app
1214 // shortcut.
1215 const gfx::NativeWindow native_window =
1216 browser()->window()->GetNativeWindow();
1217 ash::ShelfID shelf_id =
1218 ash::ShelfID::Deserialize(native_window->GetProperty(ash::kShelfIDKey));
1219 EXPECT_EQ(web_app_id, shelf_id.app_id);
1220 std::string* app_id = native_window->GetProperty(ash::kAppIDKey);
1221 ASSERT_TRUE(app_id);
1222 EXPECT_EQ(web_app_id, *app_id);
1223 }
1224
1225 // Verifies that native browser window properties are properly set when showing
1226 // a PWA tab.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,AppIDForPWA)1227 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, AppIDForPWA) {
1228 // Start server and open test page.
1229 ASSERT_TRUE(embedded_test_server()->Start());
1230 ui_test_utils::NavigateToURL(
1231 browser(),
1232 GURL(embedded_test_server()->GetURL("/banners/manifest_test_page.html")));
1233
1234 // Install PWA.
1235 chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
1236 chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA);
1237 const web_app::AppId app_id = web_app::AwaitNextInstallWithOsHooks(profile());
1238 chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
1239
1240 // Find the native window for the app.
1241 gfx::NativeWindow native_window = nullptr;
1242 for (Browser* browser : *BrowserList::GetInstance()) {
1243 if (browser->app_controller() &&
1244 browser->app_controller()->GetAppId() == app_id) {
1245 native_window = browser->window()->GetNativeWindow();
1246 break;
1247 }
1248 }
1249 ASSERT_TRUE(native_window);
1250
1251 // The native window shelf ID and app ID should match the web app ID.
1252 ash::ShelfID shelf_id =
1253 ash::ShelfID::Deserialize(native_window->GetProperty(ash::kShelfIDKey));
1254 EXPECT_EQ(app_id, shelf_id.app_id);
1255 std::string* window_app_id = native_window->GetProperty(ash::kAppIDKey);
1256 ASSERT_TRUE(window_app_id);
1257 EXPECT_EQ(app_id, *window_app_id);
1258 }
1259
1260 // Launches an app in the background and then tries to open it. This is test for
1261 // a crash we had.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchInBackground)1262 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchInBackground) {
1263 TabStripModel* tab_strip = browser()->tab_strip_model();
1264 int tab_count = tab_strip->count();
1265 LoadAndLaunchExtension(
1266 "app1",
1267 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
1268 WindowOpenDisposition::NEW_BACKGROUND_TAB,
1269 true /* prefer_containner */));
1270 EXPECT_EQ(++tab_count, tab_strip->count());
1271 controller_->LaunchApp(ash::ShelfID(last_loaded_extension_id()),
1272 ash::LAUNCH_FROM_UNKNOWN, 0,
1273 display::kInvalidDisplayId);
1274 }
1275
1276 // Confirm that clicking a icon for an app running in one of 2 maximized windows
1277 // activates the right window.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchMaximized)1278 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchMaximized) {
1279 browser()->window()->Maximize();
1280 // Load about:blank in a new window.
1281 Browser* browser2 = CreateBrowser(browser()->profile());
1282 EXPECT_NE(browser(), browser2);
1283 TabStripModel* tab_strip = browser2->tab_strip_model();
1284 int tab_count = tab_strip->count();
1285 browser2->window()->Maximize();
1286
1287 ash::ShelfID shortcut_id = CreateShortcut("app1");
1288 SelectItemAndFlushMojoCallsForAppService(shortcut_id);
1289 EXPECT_EQ(++tab_count, tab_strip->count());
1290 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1291
1292 // Activate the first browser window.
1293 browser()->window()->Activate();
1294 EXPECT_FALSE(browser2->window()->IsActive());
1295
1296 // Selecting the shortcut activates the second window.
1297 SelectItemAndFlushMojoCallsForAppService(shortcut_id);
1298 EXPECT_TRUE(browser2->window()->IsActive());
1299 }
1300
1301 // Activating the same app multiple times should launch only a single copy.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,ActivateApp)1302 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, ActivateApp) {
1303 TabStripModel* tab_strip = browser()->tab_strip_model();
1304 int tab_count = tab_strip->count();
1305 const Extension* extension =
1306 LoadExtension(test_data_dir_.AppendASCII("app1"));
1307 ActivateAppAndFlushMojoCallsForAppService(
1308 extension->id(), ash::LAUNCH_FROM_UNKNOWN, 0, display::kInvalidDisplayId);
1309 EXPECT_EQ(++tab_count, tab_strip->count());
1310 ActivateAppAndFlushMojoCallsForAppService(
1311 extension->id(), ash::LAUNCH_FROM_UNKNOWN, 0, display::kInvalidDisplayId);
1312 EXPECT_EQ(tab_count, tab_strip->count());
1313 }
1314
1315 // Launching the same app multiple times should launch a copy for each call.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,LaunchApp)1316 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchApp) {
1317 TabStripModel* tab_strip = browser()->tab_strip_model();
1318 int tab_count = tab_strip->count();
1319 ash::ShelfID id(LoadExtension(test_data_dir_.AppendASCII("app1"))->id());
1320 LaunchAppAndFlushMojoCallsForAppService(id, ash::LAUNCH_FROM_UNKNOWN, 0,
1321 display::kInvalidDisplayId);
1322 EXPECT_EQ(++tab_count, tab_strip->count());
1323 LaunchAppAndFlushMojoCallsForAppService(id, ash::LAUNCH_FROM_UNKNOWN, 0,
1324 display::kInvalidDisplayId);
1325 EXPECT_EQ(++tab_count, tab_strip->count());
1326 }
1327
1328 // The Browsertest verifying FilesManager's features.
1329 class FilesManagerExtensionTest : public LauncherPlatformAppBrowserTest {
1330 public:
SetUpOnMainThread()1331 void SetUpOnMainThread() override {
1332 LauncherPlatformAppBrowserTest::SetUpOnMainThread();
1333 CHECK(profile());
1334
1335 file_manager::test::AddDefaultComponentExtensionsOnMainThread(profile());
1336 }
1337 };
1338
1339 // Verifies that FilesManager's first shelf context menu item is "New window"
1340 // (see https://crbug.com/1102781).
IN_PROC_BROWSER_TEST_F(FilesManagerExtensionTest,VerifyFirstItem)1341 IN_PROC_BROWSER_TEST_F(FilesManagerExtensionTest, VerifyFirstItem) {
1342 const auto* extension =
1343 extensions::ExtensionRegistryFactory::GetForBrowserContext(profile())
1344 ->GetExtensionById(extension_misc::kFilesManagerAppId,
1345 extensions::ExtensionRegistry::ENABLED);
1346 EXPECT_TRUE(extension);
1347
1348 // Hacky way to configure FileManager's "New window" menu option.
1349 const std::string top_level_item_label("New window");
1350 {
1351 extensions::MenuItem::Type type = extensions::MenuItem::NORMAL;
1352
1353 // |contexts| must contain MenuItem::LAUNCHER. Otherwise the menu item will
1354 // be ignored by AppServiceShelfContextMenu.
1355 extensions::MenuItem::ContextList contexts(extensions::MenuItem::LAUNCHER);
1356
1357 extensions::MenuItem::Id id(
1358 /*incognite=*/false,
1359 extensions::MenuItem::ExtensionKey(extension->id()));
1360 std::unique_ptr<extensions::MenuItem> top_item =
1361 std::make_unique<extensions::MenuItem>(
1362 id, top_level_item_label, /*checked=*/false, /*visible=*/true,
1363 /*enabled=*/true, type, contexts);
1364 extensions::MenuManager::Get(profile())->AddContextItem(
1365 extension, std::move(top_item));
1366 apps::AppServiceProxyFactory::GetForProfile(profile())
1367 ->FlushMojoCallsForTesting();
1368 }
1369
1370 CreateAppShortcutLauncherItem(ash::ShelfID(extension->id()));
1371
1372 const int item_count = shelf_model()->item_count();
1373 ash::ShelfItem item = shelf_model()->items()[item_count - 1];
1374 int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
1375 auto menu = ShelfContextMenu::Create(controller_, &item, display_id);
1376
1377 // Fetch |extension|'s shelf context menu model and verify that the top level
1378 // menu item should be the first one.
1379 base::RunLoop run_loop;
1380 menu->GetMenuModel(base::BindLambdaForTesting(
1381 [&](std::unique_ptr<ui::SimpleMenuModel> menu_model) {
1382 EXPECT_EQ(base::ASCIIToUTF16(top_level_item_label),
1383 menu_model->GetLabelAt(0));
1384 run_loop.Quit();
1385 }));
1386
1387 run_loop.Run();
1388 }
1389
1390 // Launching an app from the shelf when not in Demo Mode should not record app
1391 // launch stat.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,NoDemoModeAppLaunchSourceReported)1392 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, NoDemoModeAppLaunchSourceReported) {
1393 EXPECT_FALSE(chromeos::DemoSession::IsDeviceInDemoMode());
1394
1395 base::HistogramTester histogram_tester;
1396
1397 // Should see 0 apps launched from the Shelf in the histogram at first.
1398 histogram_tester.ExpectTotalCount("DemoMode.AppLaunchSource", 0);
1399
1400 ash::ShelfID id(LoadExtension(test_data_dir_.AppendASCII("app1"))->id());
1401 controller_->LaunchApp(id, ash::LAUNCH_FROM_SHELF, 0,
1402 display::kInvalidDisplayId);
1403
1404 // Should still see 0 apps launched from the Shelf in the histogram.
1405 histogram_tester.ExpectTotalCount("DemoMode.AppLaunchSource", 0);
1406 }
1407
1408 // Launching an app from the shelf in Demo Mode should record app
1409 // launch stat.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,DemoModeAppLaunchSourceReported)1410 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, DemoModeAppLaunchSourceReported) {
1411 // Set Demo mode
1412 chromeos::DemoSession::SetDemoConfigForTesting(
1413 chromeos::DemoSession::DemoModeConfig::kOnline);
1414 EXPECT_TRUE(chromeos::DemoSession::IsDeviceInDemoMode());
1415
1416 base::HistogramTester histogram_tester;
1417
1418 // Should see 0 apps launched from the Shelf in the histogram at first.
1419 histogram_tester.ExpectTotalCount("DemoMode.AppLaunchSource", 0);
1420
1421 ash::ShelfID id(LoadExtension(test_data_dir_.AppendASCII("app1"))->id());
1422 controller_->LaunchApp(id, ash::LAUNCH_FROM_SHELF, 0,
1423 display::kInvalidDisplayId);
1424
1425 // Should see 1 app launched from the shelf in the histogram.
1426 histogram_tester.ExpectUniqueSample(
1427 "DemoMode.AppLaunchSource",
1428 chromeos::DemoSession::AppLaunchSource::kShelf, 1);
1429 }
1430
1431 // Confirm that a page can be navigated from and to while maintaining the
1432 // correct running state.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,Navigation)1433 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, Navigation) {
1434 ash::ShelfID shortcut_id = CreateShortcut("app1");
1435 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1436 SelectItemAndFlushMojoCallsForAppService(shortcut_id);
1437 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1438
1439 // Navigate away.
1440 ui_test_utils::NavigateToURL(browser(),
1441 GURL("http://www.example.com/path0/bar.html"));
1442 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1443
1444 // Navigate back.
1445 ui_test_utils::NavigateToURL(browser(),
1446 GURL("http://www.example.com/path1/foo.html"));
1447 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1448 }
1449
1450 // Confirm that a tab can be moved between browsers while maintaining the
1451 // correct running state.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,TabDragAndDrop)1452 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, TabDragAndDrop) {
1453 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
1454 TabStripModel* tab_strip_model1 = browser()->tab_strip_model();
1455 EXPECT_EQ(1, tab_strip_model1->count());
1456 const int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
1457 EXPECT_GE(browser_index, 0);
1458
1459 // Create a shortcut for app1.
1460 ash::ShelfID shortcut_id = CreateShortcut("app1");
1461 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
1462 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1463
1464 // Activate app1 and check its item status.
1465 SelectItemAndFlushMojoCallsForAppService(shortcut_id);
1466 EXPECT_EQ(2, tab_strip_model1->count());
1467 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
1468 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1469
1470 // Create a new browser with blank tab.
1471 Browser* browser2 = CreateBrowser(profile());
1472 EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
1473 TabStripModel* tab_strip_model2 = browser2->tab_strip_model();
1474 EXPECT_EQ(1, tab_strip_model2->count());
1475 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
1476 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1477
1478 // Detach a tab at index 1 (app1) from |tab_strip_model1| and insert it as an
1479 // active tab at index 1 to |tab_strip_model2|.
1480 std::unique_ptr<content::WebContents> detached_tab =
1481 tab_strip_model1->DetachWebContentsAt(1);
1482 tab_strip_model2->InsertWebContentsAt(1, std::move(detached_tab),
1483 TabStripModel::ADD_ACTIVE);
1484 EXPECT_EQ(1, tab_strip_model1->count());
1485 EXPECT_EQ(2, tab_strip_model2->count());
1486 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
1487 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1488
1489 tab_strip_model1->CloseAllTabs();
1490 tab_strip_model2->CloseAllTabs();
1491 }
1492
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,RefocusFilterLaunch)1493 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, RefocusFilterLaunch) {
1494 TabStripModel* tab_strip = browser()->tab_strip_model();
1495 int tab_count = tab_strip->count();
1496 ash::ShelfID shortcut_id = CreateShortcut("app1");
1497 controller_->SetRefocusURLPatternForTest(
1498 shortcut_id, GURL("http://www.example.com/path1/*"));
1499
1500 // Create new tab.
1501 ui_test_utils::NavigateToURLWithDisposition(
1502 browser(), GURL("http://www.example2.com/path2/bar.html"),
1503 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1504 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
1505 EXPECT_EQ(++tab_count, tab_strip->count());
1506 WebContents* first_tab = tab_strip->GetActiveWebContents();
1507 // Confirm app is not active.
1508 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1509
1510 // Activating app should launch new tab, because second tab isn't
1511 // in its refocus url path.
1512 SelectItemAndFlushMojoCallsForAppService(shortcut_id);
1513 EXPECT_EQ(++tab_count, tab_strip->count());
1514 WebContents* second_tab = tab_strip->GetActiveWebContents();
1515 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1516 EXPECT_NE(first_tab, second_tab);
1517 EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab);
1518 }
1519
1520 // Check that the launcher activation state for a V1 application stays closed
1521 // even after an asynchronous browser event comes in after the tab got
1522 // destroyed.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,AsyncActivationStateCheck)1523 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AsyncActivationStateCheck) {
1524 TabStripModel* tab_strip = browser()->tab_strip_model();
1525
1526 ash::ShelfID shortcut_id = CreateShortcut("app1");
1527 controller_->SetRefocusURLPatternForTest(
1528 shortcut_id, GURL("http://www.example.com/path1/*"));
1529
1530 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1531
1532 // Create new tab which would be the running app.
1533 ui_test_utils::NavigateToURLWithDisposition(
1534 browser(), GURL("http://www.example.com/path1/bar.html"),
1535 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1536 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
1537
1538 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
1539 // To address the issue of crbug.com/174050, the tab we are about to close
1540 // has to be active.
1541 tab_strip->ActivateTabAt(1);
1542 EXPECT_EQ(1, tab_strip->active_index());
1543
1544 // Close the web contents.
1545 tab_strip->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
1546 // The status should now be set to closed.
1547 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
1548 }
1549
1550 // Test that the App window could restore to its previous window state from
1551 // before it was closed.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,AppWindowRestoreBehaviorTest)1552 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AppWindowRestoreBehaviorTest) {
1553 // Open an App, maximized its window, and close it.
1554 const Extension* extension = LoadAndLaunchExtension(
1555 "app1",
1556 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
1557 WindowOpenDisposition::NEW_WINDOW,
1558 false /* prefer_containner */));
1559 Browser* app_browser = FindBrowserForApp(extension->id());
1560 ASSERT_TRUE(app_browser);
1561 BrowserWindow* window = app_browser->window();
1562 EXPECT_FALSE(window->IsMaximized());
1563 window->Maximize();
1564 EXPECT_TRUE(window->IsMaximized());
1565 CloseAppBrowserWindow(app_browser);
1566
1567 // Reopen the App. It should start maximized. Un-maximize it and close it.
1568 extension = LoadAndLaunchExtension(
1569 "app1",
1570 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
1571 WindowOpenDisposition::NEW_WINDOW,
1572 false /* prefer_containner */));
1573 app_browser = FindBrowserForApp(extension->id());
1574 ASSERT_TRUE(app_browser);
1575 window = app_browser->window();
1576 EXPECT_TRUE(window->IsMaximized());
1577
1578 window->Restore();
1579 EXPECT_FALSE(window->IsMaximized());
1580 app_browser->window()->Close();
1581 CloseAppBrowserWindow(app_browser);
1582
1583 // Reopen the App. It should start un-maximized.
1584 extension = LoadAndLaunchExtension(
1585 "app1",
1586 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
1587 WindowOpenDisposition::NEW_WINDOW,
1588 false /* prefer_containner */));
1589 app_browser = FindBrowserForApp(extension->id());
1590 ASSERT_TRUE(app_browser);
1591 window = app_browser->window();
1592 EXPECT_FALSE(window->IsMaximized());
1593 }
1594
1595 // Checks that a windowed application does not add an item to the browser list.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,WindowedAppDoesNotAddToBrowser)1596 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,
1597 WindowedAppDoesNotAddToBrowser) {
1598 // Get the number of items in the browser menu.
1599 size_t items = NumberOfDetectedLauncherBrowsers(false);
1600 size_t running_browser = chrome::GetTotalBrowserCount();
1601 EXPECT_EQ(0u, items);
1602 EXPECT_EQ(0u, running_browser);
1603
1604 const Extension* extension = LoadAndLaunchExtension(
1605 "app1",
1606 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
1607 WindowOpenDisposition::NEW_WINDOW,
1608 false /* prefer_containner */));
1609 ASSERT_TRUE(extension);
1610
1611 // No new browser should get detected, even though one more is running.
1612 EXPECT_EQ(0u, NumberOfDetectedLauncherBrowsers(false));
1613 EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
1614
1615 apps::AppServiceProxy* proxy =
1616 apps::AppServiceProxyFactory::GetForProfile(profile());
1617 proxy->Launch(
1618 extension->id(),
1619 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
1620 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1621 true /* prefer_containner */),
1622 apps::mojom::LaunchSource::kFromTest,
1623 display::Screen::GetScreen()->GetPrimaryDisplay().id());
1624 proxy->FlushMojoCallsForTesting();
1625
1626 // A new browser should get detected and one more should be running.
1627 EXPECT_EQ(NumberOfDetectedLauncherBrowsers(false), 1u);
1628 EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
1629 }
1630
1631 // Checks the functionality to enumerate all browsers vs. all tabs.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,EnumerateAllBrowsersAndTabs)1632 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,
1633 EnumerateAllBrowsersAndTabs) {
1634 // Create at least one browser.
1635 LoadAndLaunchExtension(
1636 "app1",
1637 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
1638 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1639 true /* prefer_containner */));
1640 size_t browsers = NumberOfDetectedLauncherBrowsers(false);
1641 size_t tabs = NumberOfDetectedLauncherBrowsers(true);
1642
1643 // Create a second browser.
1644 //
1645 // TODO(crbug.com/1061843): Replace OpenApplication with AppService's launch
1646 // interfaces.
1647 const Extension* extension = extension_registry()->GetExtensionById(
1648 last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED);
1649 EXPECT_TRUE(extension);
1650 apps::AppServiceProxyFactory::GetForProfile(profile())
1651 ->BrowserAppLauncher()
1652 ->LaunchAppWithParams(apps::AppLaunchParams(
1653 extension->id(), extensions::LaunchContainer::kLaunchContainerTab,
1654 WindowOpenDisposition::NEW_WINDOW,
1655 apps::mojom::AppLaunchSource::kSourceTest));
1656
1657 EXPECT_EQ(++browsers, NumberOfDetectedLauncherBrowsers(false));
1658 EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
1659
1660 // Create only a tab.
1661 LoadAndLaunchExtension(
1662 "app1",
1663 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
1664 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1665 true /* prefer_containner */));
1666
1667 EXPECT_EQ(browsers, NumberOfDetectedLauncherBrowsers(false));
1668 EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
1669 }
1670
1671 // Check that the keyboard activation of a launcher item tabs properly through
1672 // the items at hand.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,AltNumberTabsTabbing)1673 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AltNumberTabsTabbing) {
1674 TabStripModel* tab_strip = browser()->tab_strip_model();
1675
1676 ash::ShelfID shortcut_id = CreateShortcut("app");
1677 controller_->SetRefocusURLPatternForTest(
1678 shortcut_id, GURL("http://www.example.com/path/*"));
1679 std::string url = "http://www.example.com/path/bla";
1680
1681 // Create an application handled browser tab.
1682 ui_test_utils::NavigateToURLWithDisposition(
1683 browser(), GURL(url), WindowOpenDisposition::NEW_FOREGROUND_TAB,
1684 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
1685
1686 content::WebContents* content1 = tab_strip->GetActiveWebContents();
1687
1688 // Create some other browser tab.
1689 ui_test_utils::NavigateToURLWithDisposition(
1690 browser(), GURL("http://www.test.com"),
1691 WindowOpenDisposition::NEW_FOREGROUND_TAB,
1692 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
1693 content::WebContents* content1a = tab_strip->GetActiveWebContents();
1694
1695 // Make sure that the active tab is now our handled tab.
1696 EXPECT_NE(content1a, content1);
1697
1698 // The active tab should still be the unnamed tab. Then we switch and reach
1699 // the first app and stay there.
1700 EXPECT_EQ(content1a, tab_strip->GetActiveWebContents());
1701 SelectItem(shortcut_id, ui::ET_KEY_RELEASED);
1702 EXPECT_EQ(content1, tab_strip->GetActiveWebContents());
1703 SelectItem(shortcut_id, ui::ET_KEY_RELEASED);
1704 EXPECT_EQ(content1, tab_strip->GetActiveWebContents());
1705
1706 ui_test_utils::NavigateToURLWithDisposition(
1707 browser(), GURL(url), WindowOpenDisposition::NEW_FOREGROUND_TAB,
1708 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
1709 content::WebContents* content2 = tab_strip->GetActiveWebContents();
1710
1711 EXPECT_EQ(content2, browser()->tab_strip_model()->GetActiveWebContents());
1712 SelectItem(shortcut_id, ui::ET_KEY_RELEASED);
1713 EXPECT_EQ(content1, browser()->tab_strip_model()->GetActiveWebContents());
1714 SelectItem(shortcut_id, ui::ET_KEY_RELEASED);
1715 EXPECT_EQ(content2, browser()->tab_strip_model()->GetActiveWebContents());
1716 }
1717
1718 // Check that the keyboard activation of a launcher item tabs properly through
1719 // the items at hand.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,AltNumberAppsTabbing)1720 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, AltNumberAppsTabbing) {
1721 // First run app.
1722 const Extension* extension1 = LoadAndLaunchPlatformApp("launch", "Launched");
1723 ui::BaseWindow* window1 =
1724 CreateAppWindow(browser()->profile(), extension1)->GetBaseWindow();
1725
1726 const ash::ShelfItem item = GetLastLauncherItem();
1727 EXPECT_EQ(ash::TYPE_APP, item.type);
1728 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
1729
1730 const Extension* extension2 =
1731 LoadAndLaunchPlatformApp("launch_2", "Launched");
1732 ui::BaseWindow* window2 =
1733 CreateAppWindow(browser()->profile(), extension2)->GetBaseWindow();
1734
1735 // By now the browser should be active. Issue Alt keystrokes several times to
1736 // see that we stay on that application.
1737 EXPECT_TRUE(window2->IsActive());
1738 SelectItem(item.id, ui::ET_KEY_RELEASED);
1739 EXPECT_TRUE(window1->IsActive());
1740 SelectItem(item.id, ui::ET_KEY_RELEASED);
1741 EXPECT_TRUE(window1->IsActive());
1742
1743 ui::BaseWindow* window1a =
1744 CreateAppWindow(browser()->profile(), extension1)->GetBaseWindow();
1745
1746 EXPECT_TRUE(window1a->IsActive());
1747 EXPECT_FALSE(window1->IsActive());
1748 SelectItem(item.id, ui::ET_KEY_RELEASED);
1749 EXPECT_TRUE(window1->IsActive());
1750 SelectItem(item.id, ui::ET_KEY_RELEASED);
1751 EXPECT_TRUE(window1a->IsActive());
1752 }
1753
1754 // Check that the keyboard activation of a launcher item tabs even if the app is
1755 // not currently activated.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,AltNumberAppsTabbingFromOtherApp)1756 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,
1757 AltNumberAppsTabbingFromOtherApp) {
1758 // Create one app with two windows.
1759 const Extension* app1_extension1 =
1760 LoadAndLaunchPlatformApp("launch", "Launched");
1761 ui::BaseWindow* app1_window1 =
1762 CreateAppWindow(browser()->profile(), app1_extension1)->GetBaseWindow();
1763 ui::BaseWindow* app1_window2 =
1764 CreateAppWindow(browser()->profile(), app1_extension1)->GetBaseWindow();
1765 const ash::ShelfItem item1 = GetLastLauncherItem();
1766 EXPECT_EQ(ash::TYPE_APP, item1.type);
1767 EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
1768
1769 // Create another app with two windows.
1770 const Extension* app2_extension1 =
1771 LoadAndLaunchPlatformApp("launch_2", "Launched");
1772 ui::BaseWindow* app2_window1 =
1773 CreateAppWindow(browser()->profile(), app2_extension1)->GetBaseWindow();
1774 ui::BaseWindow* app2_window2 =
1775 CreateAppWindow(browser()->profile(), app2_extension1)->GetBaseWindow();
1776 const ash::ShelfItem item2 = GetLastLauncherItem();
1777 EXPECT_EQ(ash::TYPE_APP, item2.type);
1778 EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
1779
1780 // Last created window should be active. Hitting the app shortcut should go to
1781 // the first window of the app.
1782 ASSERT_TRUE(app2_window2->IsActive());
1783 SelectItem(item2.id, ui::ET_KEY_RELEASED);
1784 EXPECT_TRUE(app2_window1->IsActive());
1785
1786 // Hitting the other app's shortcut should jump and focus the other app's
1787 // windows.
1788 SelectItem(item1.id, ui::ET_KEY_RELEASED);
1789 EXPECT_TRUE(app1_window2->IsActive());
1790 SelectItem(item1.id, ui::ET_KEY_RELEASED);
1791 EXPECT_TRUE(app1_window1->IsActive());
1792 }
1793
1794 // Test that we get correct shelf presence with hidden app windows.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,HiddenAppWindows)1795 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, HiddenAppWindows) {
1796 int item_count = shelf_model()->item_count();
1797 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
1798 AppWindow::CreateParams params;
1799
1800 // Create a hidden window.
1801 params.hidden = true;
1802 AppWindow* window_1 =
1803 CreateAppWindowFromParams(browser()->profile(), extension, params);
1804 EXPECT_EQ(item_count, shelf_model()->item_count());
1805
1806 // Create a visible window.
1807 params.hidden = false;
1808 AppWindow* window_2 =
1809 CreateAppWindowFromParams(browser()->profile(), extension, params);
1810 ++item_count;
1811 EXPECT_EQ(item_count, shelf_model()->item_count());
1812
1813 // Minimize the visible window.
1814 window_2->Minimize();
1815 EXPECT_EQ(item_count, shelf_model()->item_count());
1816
1817 // Hide the visible window.
1818 window_2->Hide();
1819 --item_count;
1820 EXPECT_EQ(item_count, shelf_model()->item_count());
1821
1822 // Show the originally hidden window.
1823 window_1->Show(AppWindow::SHOW_ACTIVE);
1824 ++item_count;
1825 EXPECT_EQ(item_count, shelf_model()->item_count());
1826
1827 // Close the originally hidden window.
1828 CloseAppWindow(window_1);
1829 --item_count;
1830 EXPECT_EQ(item_count, shelf_model()->item_count());
1831 }
1832
1833 // Test attention states of windows.
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,WindowAttentionStatus)1834 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, WindowAttentionStatus) {
1835 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
1836 AppWindow::CreateParams params;
1837 params.focused = false;
1838 AppWindow* window =
1839 CreateAppWindowFromParams(browser()->profile(), extension, params);
1840 EXPECT_TRUE(window->GetNativeWindow()->IsVisible());
1841 // The window should not be active by default.
1842 EXPECT_FALSE(window->GetBaseWindow()->IsActive());
1843 // Confirm that a shelf item was created and is the correct state.
1844 const ash::ShelfItem& item = GetLastLauncherItem();
1845 EXPECT_TRUE(GetShelfItemDelegate(item.id));
1846 EXPECT_EQ(ash::TYPE_APP, item.type);
1847 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
1848
1849 // App windows should go to attention state.
1850 window->GetNativeWindow()->SetProperty(aura::client::kDrawAttentionKey, true);
1851 EXPECT_EQ(ash::STATUS_ATTENTION, item.status);
1852
1853 // Click the item and confirm that the window is activated.
1854 EXPECT_EQ(ash::SHELF_ACTION_WINDOW_ACTIVATED, SelectItem(item.id));
1855 EXPECT_TRUE(window->GetBaseWindow()->IsActive());
1856
1857 // Active windows don't show attention.
1858 window->GetNativeWindow()->SetProperty(aura::client::kDrawAttentionKey, true);
1859 EXPECT_EQ(ash::STATUS_RUNNING, item.status);
1860 }
1861
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,ShowInShelfWindowsWithWindowKeySet)1862 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,
1863 ShowInShelfWindowsWithWindowKeySet) {
1864 // Add a window with shelf True, close it
1865 int item_count = shelf_model()->item_count();
1866 const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched");
1867 AppWindow::CreateParams params;
1868
1869 params.show_in_shelf = true;
1870 params.window_key = "window1";
1871 AppWindow* window1 =
1872 CreateAppWindowFromParams(browser()->profile(), extension, params);
1873 // There should be only 1 item added to the shelf.
1874 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1875 CloseAppWindow(window1);
1876 EXPECT_EQ(item_count, shelf_model()->item_count());
1877
1878 // Add a window with false, following one with true
1879 item_count = shelf_model()->item_count();
1880 extension = LoadAndLaunchPlatformApp("launch", "Launched");
1881
1882 params.show_in_shelf = false;
1883 params.window_key = "window1";
1884 window1 = CreateAppWindowFromParams(browser()->profile(), extension, params);
1885 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1886 params.show_in_shelf = true;
1887 params.window_key = "window2";
1888 AppWindow* window2 =
1889 CreateAppWindowFromParams(browser()->profile(), extension, params);
1890 // There should be 2 items added to the shelf: although window1 has
1891 // show_in_shelf set to false, it's the first window created so its icon must
1892 // show up in shelf.
1893 EXPECT_EQ(item_count + 2, shelf_model()->item_count());
1894 CloseAppWindow(window1);
1895 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1896 CloseAppWindow(window2);
1897 EXPECT_EQ(item_count, shelf_model()->item_count());
1898
1899 // Open just one window with false
1900 item_count = shelf_model()->item_count();
1901 extension = LoadAndLaunchPlatformApp("launch", "Launched");
1902
1903 params.show_in_shelf = false;
1904 params.window_key = "window1";
1905 window1 = CreateAppWindowFromParams(browser()->profile(), extension, params);
1906 // There should be 1 item added to the shelf: although show_in_shelf is false,
1907 // this is the first window created.
1908 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1909 CloseAppWindow(window1);
1910 EXPECT_EQ(item_count, shelf_model()->item_count());
1911
1912 // Add a window with true, following one with false
1913 item_count = shelf_model()->item_count();
1914 extension = LoadAndLaunchPlatformApp("launch", "Launched");
1915
1916 params.show_in_shelf = true;
1917 params.window_key = "window1";
1918 window1 = CreateAppWindowFromParams(browser()->profile(), extension, params);
1919 EXPECT_EQ(item_count + 1, shelf_model()->item_count()); // main window
1920 params.show_in_shelf = false;
1921 params.window_key = "window2";
1922 window2 = CreateAppWindowFromParams(browser()->profile(), extension, params);
1923 EXPECT_EQ(item_count + 2, shelf_model()->item_count());
1924 CloseAppWindow(window1);
1925 // There should be 1 item added to the shelf as the second window
1926 // is set to show_in_shelf false
1927 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1928 CloseAppWindow(window2);
1929 EXPECT_EQ(item_count, shelf_model()->item_count());
1930
1931 // Test closing windows in different order
1932 item_count = shelf_model()->item_count();
1933 extension = LoadAndLaunchPlatformApp("launch", "Launched");
1934
1935 params.show_in_shelf = false;
1936 params.window_key = "window1";
1937 window1 = CreateAppWindowFromParams(browser()->profile(), extension, params);
1938 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1939 params.show_in_shelf = false;
1940 params.window_key = "window2";
1941 window2 = CreateAppWindowFromParams(browser()->profile(), extension, params);
1942 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1943 params.show_in_shelf = true;
1944 params.window_key = "window3";
1945 AppWindow* window3 =
1946 CreateAppWindowFromParams(browser()->profile(), extension, params);
1947 EXPECT_EQ(item_count + 2, shelf_model()->item_count());
1948 params.show_in_shelf = true;
1949 params.window_key = "window4";
1950 AppWindow* window4 =
1951 CreateAppWindowFromParams(browser()->profile(), extension, params);
1952 // There should be 3 items added to the shelf.
1953 EXPECT_EQ(item_count + 3, shelf_model()->item_count());
1954 // Any window close order should be valid
1955 CloseAppWindow(window4);
1956 // Closed window4 that was shown in shelf. item_count would decrease
1957 EXPECT_EQ(item_count + 2, shelf_model()->item_count());
1958 CloseAppWindow(window1);
1959 // Closed window1 which was grouped together with window2 so item_count
1960 // would not decrease
1961 EXPECT_EQ(item_count + 2, shelf_model()->item_count());
1962 CloseAppWindow(window3);
1963 // Closed window3 that was shown in shelf. item_count would decrease
1964 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
1965 CloseAppWindow(window2);
1966 // Closed window2 - there is no other window in that group and item_count
1967 // would decrease
1968 EXPECT_EQ(item_count, shelf_model()->item_count());
1969 }
1970
1971 // Checks that the browser Alt "tabbing" is properly done.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,AltNumberBrowserTabbing)1972 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,
1973 AltNumberBrowserTabbing) {
1974 // Get the number of items in the browser menu.
1975 EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
1976 // The first activation should create a browser at index 2 (App List @ 0 and
1977 // back button @ 1).
1978 const ash::ShelfID browser_id = shelf_model()->items()[0].id;
1979 SelectItem(browser_id, ui::ET_KEY_RELEASED);
1980 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
1981 // A second activation should not create a new instance.
1982 SelectItem(browser_id, ui::ET_KEY_RELEASED);
1983 Browser* browser1 = chrome::FindLastActive();
1984 EXPECT_TRUE(browser1);
1985 Browser* browser2 = CreateBrowser(profile());
1986
1987 EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
1988 EXPECT_NE(browser1->window(), browser2->window());
1989 EXPECT_TRUE(browser2->window()->IsActive());
1990
1991 // Activate multiple times the switcher to see that the windows get activated.
1992 SelectItem(browser_id, ui::ET_KEY_RELEASED);
1993 EXPECT_TRUE(browser1->window()->IsActive());
1994 SelectItem(browser_id, ui::ET_KEY_RELEASED);
1995 EXPECT_TRUE(browser2->window()->IsActive());
1996
1997 // Create a third browser - make sure that we do not toggle simply between
1998 // two windows.
1999 Browser* browser3 = CreateBrowser(profile());
2000
2001 EXPECT_EQ(3u, chrome::GetTotalBrowserCount());
2002 EXPECT_NE(browser1->window(), browser3->window());
2003 EXPECT_NE(browser2->window(), browser3->window());
2004 EXPECT_TRUE(browser3->window()->IsActive());
2005
2006 SelectItem(browser_id, ui::ET_KEY_RELEASED);
2007 EXPECT_TRUE(browser1->window()->IsActive());
2008 SelectItem(browser_id, ui::ET_KEY_RELEASED);
2009 EXPECT_TRUE(browser2->window()->IsActive());
2010 SelectItem(browser_id, ui::ET_KEY_RELEASED);
2011 EXPECT_TRUE(browser3->window()->IsActive());
2012 SelectItem(browser_id, ui::ET_KEY_RELEASED);
2013 EXPECT_TRUE(browser1->window()->IsActive());
2014
2015 // Create another app and make sure that none of our browsers is active.
2016 LoadAndLaunchExtension(
2017 "app1",
2018 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
2019 WindowOpenDisposition::NEW_WINDOW,
2020 false /* prefer_containner */));
2021 EXPECT_FALSE(browser1->window()->IsActive());
2022 EXPECT_FALSE(browser2->window()->IsActive());
2023
2024 // After activation our browser should be active again.
2025 SelectItem(browser_id, ui::ET_KEY_RELEASED);
2026 EXPECT_TRUE(browser1->window()->IsActive());
2027 }
2028
2029 // Checks that after a session restore, we do not start applications on an
2030 // activation.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,ActivateAfterSessionRestore)2031 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, ActivateAfterSessionRestore) {
2032 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
2033
2034 // Create a known application.
2035 ash::ShelfID shortcut_id = CreateShortcut("app1");
2036
2037 // Create a new browser - without activating it - and load an "app" into it.
2038 Browser::CreateParams params = Browser::CreateParams(profile(), true);
2039 params.initial_show_state = ui::SHOW_STATE_INACTIVE;
2040 Browser* browser2 = Browser::Create(params);
2041 controller_->SetRefocusURLPatternForTest(
2042 shortcut_id, GURL("http://www.example.com/path/*"));
2043 std::string url = "http://www.example.com/path/bla";
2044 ui_test_utils::NavigateToURLWithDisposition(
2045 browser2, GURL(url), WindowOpenDisposition::NEW_FOREGROUND_TAB,
2046 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
2047
2048 // Remember the number of tabs for each browser.
2049 TabStripModel* tab_strip = browser()->tab_strip_model();
2050 int tab_count1 = tab_strip->count();
2051 TabStripModel* tab_strip2 = browser2->tab_strip_model();
2052 int tab_count2 = tab_strip2->count();
2053
2054 // Check that we have two browsers and the inactive browser remained inactive.
2055 EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
2056 EXPECT_EQ(chrome::FindLastActive(), browser());
2057 EXPECT_TRUE(browser()->window()->IsActive());
2058 // Check that the LRU browser list does only contain the original browser.
2059 BrowserList* browser_list = BrowserList::GetInstance();
2060 BrowserList::const_reverse_iterator it = browser_list->begin_last_active();
2061 EXPECT_EQ(*it, browser());
2062 ++it;
2063 EXPECT_EQ(it, browser_list->end_last_active());
2064
2065 // Now request to either activate an existing app or create a new one.
2066 SelectItem(shortcut_id);
2067
2068 // Check that we have set focus on the existing application and nothing new
2069 // was created.
2070 EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
2071 EXPECT_EQ(tab_count1, tab_strip->count());
2072 EXPECT_EQ(tab_count2, tab_strip2->count());
2073 EXPECT_EQ(chrome::FindLastActive(), browser2);
2074 EXPECT_TRUE(browser2->window()->IsActive());
2075 }
2076
2077 // TODO(crbug.com/759779, crbug.com/819386): add back |DISABLED_DragAndDrop|.
2078 // TODO(crbug.com/759779, crbug.com/819386): add back
2079 // |MultiDisplayBasicDragAndDrop|.
2080
2081 // TODO(crbug.com/759779, crbug.com/819386): add back |ClickItem|.
2082
2083 // Check browser shortcut item functionality.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,BrowserShortcutLauncherItemController)2084 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,
2085 BrowserShortcutLauncherItemController) {
2086 ash::ShelfItemDelegate* item_controller =
2087 controller_->GetBrowserShortcutLauncherItemController();
2088 EXPECT_TRUE(item_controller);
2089 const ash::ShelfID browser_id = item_controller->shelf_id();
2090 EXPECT_EQ(extension_misc::kChromeAppId, browser_id.app_id);
2091
2092 extensions::ExtensionPrefs* prefs =
2093 extensions::ExtensionPrefs::Get(profile());
2094
2095 // Get the number of browsers.
2096 size_t running_browser = chrome::GetTotalBrowserCount();
2097 EXPECT_EQ(0u, running_browser);
2098 EXPECT_FALSE(controller_->IsOpen(browser_id));
2099 // No launch time recorded for Chrome yet.
2100 EXPECT_EQ(base::Time(),
2101 prefs->GetLastLaunchTime(extension_misc::kChromeAppId));
2102
2103 // Activate. This creates new browser
2104 base::Time time_before_launch = base::Time::Now();
2105 SelectItem(browser_id, ui::ET_UNKNOWN);
2106 base::Time time_after_launch = base::Time::Now();
2107 // New Window is created.
2108 running_browser = chrome::GetTotalBrowserCount();
2109 EXPECT_EQ(1u, running_browser);
2110 EXPECT_TRUE(controller_->IsOpen(browser_id));
2111 // Valid launch time should be recorded for Chrome.
2112 const base::Time time_launch =
2113 prefs->GetLastLaunchTime(extension_misc::kChromeAppId);
2114 EXPECT_LE(time_before_launch, time_launch);
2115 EXPECT_GE(time_after_launch, time_launch);
2116
2117 // Minimize Window.
2118 Browser* browser = chrome::FindLastActive();
2119 ASSERT_TRUE(browser);
2120 browser->window()->Minimize();
2121 EXPECT_TRUE(browser->window()->IsMinimized());
2122
2123 // Activate again. This doesn't create new browser, it activates the window.
2124 SelectItem(browser_id, ui::ET_UNKNOWN);
2125 running_browser = chrome::GetTotalBrowserCount();
2126 EXPECT_EQ(1u, running_browser);
2127 EXPECT_TRUE(controller_->IsOpen(browser_id));
2128 EXPECT_FALSE(browser->window()->IsMinimized());
2129 // Re-activation should not upate the recorded launch time.
2130 EXPECT_GE(time_launch,
2131 prefs->GetLastLaunchTime(extension_misc::kChromeAppId));
2132 }
2133
2134 // Check that browser launch time is recorded when the browser is started
2135 // by means other than BrowserShortcutLauncherItemController.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,BrowserLaunchTimeRecorded)2136 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,
2137 BrowserLaunchTimeRecorded) {
2138 extensions::ExtensionPrefs* prefs =
2139 extensions::ExtensionPrefs::Get(profile());
2140
2141 EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
2142 EXPECT_EQ(base::Time(),
2143 prefs->GetLastLaunchTime(extension_misc::kChromeAppId));
2144
2145 base::Time time_before_launch = base::Time::Now();
2146 // Load about:blank in a new window.
2147 CreateBrowser(profile());
2148 base::Time time_after_launch = base::Time::Now();
2149 const base::Time time_launch =
2150 prefs->GetLastLaunchTime(extension_misc::kChromeAppId);
2151 EXPECT_LE(time_before_launch, time_launch);
2152 EXPECT_GE(time_after_launch, time_launch);
2153 }
2154
2155 // Check that the window's ShelfID property matches that of the active tab.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,MatchingShelfIDAndActiveTab)2156 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, MatchingShelfIDAndActiveTab) {
2157 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
2158 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2159 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
2160 EXPECT_EQ(1, shelf_model()->item_count());
2161
2162 aura::Window* window = browser()->window()->GetNativeWindow();
2163
2164 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
2165 ash::ShelfID browser_id = shelf_model()->items()[browser_index].id;
2166 ash::ShelfID id =
2167 ash::ShelfID::Deserialize(window->GetProperty(ash::kShelfIDKey));
2168 EXPECT_EQ(browser_id, id);
2169 std::string* window_app_id = window->GetProperty(ash::kAppIDKey);
2170 ASSERT_TRUE(window_app_id);
2171 EXPECT_EQ(browser_id.app_id, *window_app_id);
2172
2173 ash::ShelfID app_id = CreateShortcut("app1");
2174 EXPECT_EQ(2, shelf_model()->item_count());
2175
2176 // Create and activate a new tab for "app1" and expect an application ShelfID.
2177 SelectItemAndFlushMojoCallsForAppService(app_id);
2178 EXPECT_EQ(2, browser()->tab_strip_model()->count());
2179 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
2180 id = ash::ShelfID::Deserialize(window->GetProperty(ash::kShelfIDKey));
2181 EXPECT_EQ(app_id, id);
2182
2183 window_app_id = window->GetProperty(ash::kAppIDKey);
2184 ASSERT_TRUE(window_app_id);
2185 EXPECT_EQ(app_id.app_id, *window_app_id);
2186
2187 // Activate the tab at index 0 (NTP) and expect a browser ShelfID.
2188 browser()->tab_strip_model()->ActivateTabAt(0);
2189 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
2190 id = ash::ShelfID::Deserialize(window->GetProperty(ash::kShelfIDKey));
2191 EXPECT_EQ(browser_id, id);
2192
2193 window_app_id = window->GetProperty(ash::kAppIDKey);
2194 ASSERT_TRUE(window_app_id);
2195 EXPECT_EQ(browser_id.app_id, *window_app_id);
2196 }
2197
2198 // Check that a windowed V1 application can navigate away from its domain, but
2199 // still gets detected properly.
2200 // Disabled due to https://crbug.com/838743.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,DISABLED_V1AppNavigation)2201 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, DISABLED_V1AppNavigation) {
2202 // We assume that the web store is always there (which it apparently is).
2203 controller_->PinAppWithID(extensions::kWebStoreAppId);
2204 const ash::ShelfID id(extensions::kWebStoreAppId);
2205 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(id)->status);
2206
2207 // Create a windowed application.
2208 apps::AppServiceProxy* proxy =
2209 apps::AppServiceProxyFactory::GetForProfile(profile());
2210 proxy->Launch(
2211 extensions::kWebStoreAppId,
2212 apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
2213 WindowOpenDisposition::NEW_FOREGROUND_TAB,
2214 true /* prefer_containner */),
2215 apps::mojom::LaunchSource::kFromTest,
2216 display::Screen::GetScreen()->GetPrimaryDisplay().id());
2217 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(id)->status);
2218
2219 // Find the browser which holds our app.
2220 Browser* app_browser = nullptr;
2221 const BrowserList* browser_list = BrowserList::GetInstance();
2222 for (BrowserList::const_reverse_iterator it =
2223 browser_list->begin_last_active();
2224 it != browser_list->end_last_active() && !app_browser; ++it) {
2225 if ((*it)->deprecated_is_app()) {
2226 app_browser = *it;
2227 break;
2228 }
2229 }
2230 ASSERT_TRUE(app_browser);
2231
2232 // After navigating away in the app, we should still be active.
2233 ui_test_utils::NavigateToURL(app_browser,
2234 GURL("http://www.foo.com/bar.html"));
2235 // Make sure the navigation was entirely performed.
2236 base::RunLoop().RunUntilIdle();
2237 EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(id)->status);
2238 app_browser->tab_strip_model()->CloseWebContentsAt(0,
2239 TabStripModel::CLOSE_NONE);
2240 // Make sure that the app is really gone.
2241 base::RunLoop().RunUntilIdle();
2242 EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(id)->status);
2243 }
2244
2245 // Ensure opening settings and task manager windows create new shelf items.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,SettingsAndTaskManagerWindows)2246 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, SettingsAndTaskManagerWindows) {
2247 // Install the Settings App.
2248 web_app::WebAppProvider::Get(browser()->profile())
2249 ->system_web_app_manager()
2250 .InstallSystemAppsForTesting();
2251 chrome::SettingsWindowManager* settings_manager =
2252 chrome::SettingsWindowManager::GetInstance();
2253
2254 // Get the number of items in the shelf and browser menu.
2255 int item_count = shelf_model()->item_count();
2256 ASSERT_GE(item_count, 0);
2257 size_t browser_count = NumberOfDetectedLauncherBrowsers(false);
2258
2259 // Open a settings window. Number of browser items should remain unchanged,
2260 // number of shelf items should increase.
2261 settings_manager->ShowChromePageForProfile(
2262 browser()->profile(), chrome::GetOSSettingsUrl(std::string()));
2263 // Spin a run loop to sync Ash's ShelfModel change for the settings window.
2264 base::RunLoop().RunUntilIdle();
2265 Browser* settings_browser =
2266 settings_manager->FindBrowserForProfile(browser()->profile());
2267 ASSERT_TRUE(settings_browser);
2268 EXPECT_EQ(browser_count, NumberOfDetectedLauncherBrowsers(false));
2269 EXPECT_EQ(item_count + 1, shelf_model()->item_count());
2270
2271 aura::Window* settings_window = settings_browser->window()->GetNativeWindow();
2272 ASSERT_TRUE(settings_window->GetProperty(ash::kAppIDKey));
2273 EXPECT_TRUE(crx_file::id_util::IdIsValid(
2274 *settings_window->GetProperty(ash::kAppIDKey)));
2275
2276 chrome::ShowTaskManager(browser());
2277 // Spin a run loop to sync Ash's ShelfModel change for the task manager.
2278 base::RunLoop().RunUntilIdle();
2279 EXPECT_EQ(item_count + 2, shelf_model()->item_count());
2280
2281 // Validates that all items have valid app id.
2282 for (const auto& item : shelf_model()->items())
2283 EXPECT_TRUE(crx_file::id_util::IdIsValid(item.id.app_id));
2284
2285 // TODO(stevenjb): Test multiprofile on Chrome OS when test support is addded.
2286 // crbug.com/230464.
2287 }
2288
2289 // Check that tabbed hosted and web apps have correct shelf presence.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,TabbedHostedAndWebApps)2290 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, TabbedHostedAndWebApps) {
2291 // Load and pin a hosted app.
2292 const Extension* hosted_app =
2293 LoadExtension(test_data_dir_.AppendASCII("app1/"));
2294 ASSERT_TRUE(hosted_app);
2295 controller_->PinAppWithID(hosted_app->id());
2296 const ash::ShelfID hosted_app_shelf_id(hosted_app->id());
2297
2298 // Load and pin a web app.
2299 const GURL web_app_url = GetSecureAppURL();
2300 const web_app::AppId web_app_id = InstallWebApp(web_app_url);
2301 controller_->PinAppWithID(web_app_id);
2302 const ash::ShelfID web_app_shelf_id(web_app_id);
2303
2304 // The apps should be closed.
2305 EXPECT_EQ(ash::STATUS_CLOSED,
2306 shelf_model()->ItemByID(hosted_app_shelf_id)->status);
2307 EXPECT_EQ(ash::STATUS_CLOSED,
2308 shelf_model()->ItemByID(web_app_shelf_id)->status);
2309
2310 // Navigate to the app's launch URLs in two tabs.
2311 ui_test_utils::NavigateToURL(
2312 browser(), extensions::AppLaunchInfo::GetLaunchWebURL(hosted_app));
2313 ui_test_utils::NavigateToURLWithDisposition(
2314 browser(), web_app_url, WindowOpenDisposition::NEW_FOREGROUND_TAB, 0);
2315
2316 // The apps should now be running.
2317 EXPECT_EQ(ash::STATUS_RUNNING,
2318 shelf_model()->ItemByID(hosted_app_shelf_id)->status);
2319 EXPECT_EQ(ash::STATUS_RUNNING,
2320 shelf_model()->ItemByID(web_app_shelf_id)->status);
2321
2322 // Now use the launcher controller to activate the apps.
2323 controller_->ActivateApp(hosted_app->id(), ash::LAUNCH_FROM_APP_LIST, 0,
2324 display::kInvalidDisplayId);
2325 controller_->ActivateApp(web_app_id, ash::LAUNCH_FROM_APP_LIST, 0,
2326 display::kInvalidDisplayId);
2327
2328 // There should be no new browsers or tabs as both apps were already open.
2329 EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
2330 EXPECT_EQ(2, browser()->tab_strip_model()->count());
2331 }
2332
2333 // Check that windowed hosted and web apps have correct shelf presence.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,WindowedHostedAndWebApps)2334 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, WindowedHostedAndWebApps) {
2335 // Load and pin a hosted app.
2336 const Extension* hosted_app =
2337 LoadExtension(test_data_dir_.AppendASCII("app1/"));
2338 ASSERT_TRUE(hosted_app);
2339 controller_->PinAppWithID(hosted_app->id());
2340 const ash::ShelfID hosted_app_shelf_id(hosted_app->id());
2341
2342 // Load and pin a web app.
2343 const GURL web_app_url = GetSecureAppURL();
2344 const web_app::AppId web_app_id = InstallWebApp(web_app_url);
2345 controller_->PinAppWithID(web_app_id);
2346 const ash::ShelfID web_app_shelf_id(web_app_id);
2347
2348 // Set both apps to open in windows.
2349 extensions::SetLaunchType(browser()->profile(), hosted_app->id(),
2350 extensions::LAUNCH_TYPE_WINDOW);
2351 WebAppProviderBase* provider =
2352 WebAppProviderBase::GetProviderBase(browser()->profile());
2353 DCHECK(provider);
2354 provider->registry_controller().SetAppUserDisplayMode(
2355 web_app_id, web_app::DisplayMode::kStandalone, /*is_user_action=*/false);
2356
2357 // The apps should be closed.
2358 EXPECT_EQ(ash::STATUS_CLOSED,
2359 shelf_model()->ItemByID(hosted_app_shelf_id)->status);
2360 EXPECT_EQ(ash::STATUS_CLOSED,
2361 shelf_model()->ItemByID(web_app_shelf_id)->status);
2362
2363 // Navigate to the app's launch URLs in two tabs.
2364 ui_test_utils::NavigateToURL(
2365 browser(), extensions::AppLaunchInfo::GetLaunchWebURL(hosted_app));
2366 ui_test_utils::NavigateToURLWithDisposition(
2367 browser(), web_app_url, WindowOpenDisposition::NEW_FOREGROUND_TAB, 0);
2368
2369 // The apps should still be closed.
2370 EXPECT_EQ(ash::STATUS_CLOSED,
2371 shelf_model()->ItemByID(hosted_app_shelf_id)->status);
2372 EXPECT_EQ(ash::STATUS_CLOSED,
2373 shelf_model()->ItemByID(web_app_shelf_id)->status);
2374
2375 // Now use the launcher controller to activate the apps.
2376 ActivateAppAndFlushMojoCallsForAppService(hosted_app->id(),
2377 ash::LAUNCH_FROM_APP_LIST, 0,
2378 display::kInvalidDisplayId);
2379 ActivateAppAndFlushMojoCallsForAppService(
2380 web_app_id, ash::LAUNCH_FROM_APP_LIST, 0, display::kInvalidDisplayId);
2381
2382 // There should be two new browsers.
2383 EXPECT_EQ(3u, chrome::GetBrowserCount(browser()->profile()));
2384
2385 // The apps should now be running.
2386 EXPECT_EQ(ash::STATUS_RUNNING,
2387 shelf_model()->ItemByID(hosted_app_shelf_id)->status);
2388 EXPECT_EQ(ash::STATUS_RUNNING,
2389 shelf_model()->ItemByID(web_app_shelf_id)->status);
2390 }
2391
2392 // Windowed progressive web apps should have shelf activity indicator showing
2393 // after install.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,WindowedPwasHaveActivityIndicatorSet)2394 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,
2395 WindowedPwasHaveActivityIndicatorSet) {
2396 // Start server and open test page.
2397 ASSERT_TRUE(embedded_test_server()->Start());
2398 AddTabAtIndex(
2399 1,
2400 GURL(embedded_test_server()->GetURL("/banners/manifest_test_page.html")),
2401 ui::PAGE_TRANSITION_LINK);
2402 // Install PWA.
2403 chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
2404 chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA);
2405 web_app::AppId app_id = web_app::AwaitNextInstallWithOsHooks(profile());
2406 chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
2407
2408 ash::ShelfID shelf_id(app_id);
2409 EXPECT_FALSE(ChromeLauncherController::instance()->IsPinned(shelf_id));
2410 EXPECT_EQ(
2411 shelf_id,
2412 ChromeLauncherController::instance()->shelf_model()->active_shelf_id());
2413 }
2414
2415 // Windowed shortcut apps should have shelf activity indicator showing after
2416 // install.
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,WindowedShortcutAppsHaveActivityIndicatorSet)2417 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,
2418 WindowedShortcutAppsHaveActivityIndicatorSet) {
2419 // Start server and open test page.
2420 ASSERT_TRUE(embedded_test_server()->Start());
2421 AddTabAtIndex(
2422 1,
2423 GURL(embedded_test_server()->GetURL("/banners/manifest_test_page.html")),
2424 ui::PAGE_TRANSITION_LINK);
2425 // Install shortcut app.
2426 chrome::SetAutoAcceptWebAppDialogForTesting(true, true);
2427 chrome::ExecuteCommand(browser(), IDC_CREATE_SHORTCUT);
2428 web_app::AppId app_id = web_app::AwaitNextInstallWithOsHooks(profile());
2429 chrome::SetAutoAcceptWebAppDialogForTesting(false, false);
2430
2431 ash::ShelfID shelf_id(app_id);
2432 EXPECT_FALSE(ChromeLauncherController::instance()->IsPinned(shelf_id));
2433 EXPECT_EQ(
2434 shelf_id,
2435 ChromeLauncherController::instance()->shelf_model()->active_shelf_id());
2436 }
2437
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,WebAppPolicy)2438 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, WebAppPolicy) {
2439 // Install web app.
2440 GURL app_url = GURL("https://example.org/");
2441 web_app::AppId app_id = InstallWebApp(app_url);
2442 web_app::ExternallyInstalledWebAppPrefs web_app_prefs(
2443 browser()->profile()->GetPrefs());
2444 web_app_prefs.Insert(app_url, app_id,
2445 web_app::ExternalInstallSource::kExternalPolicy);
2446 apps::AppServiceProxyFactory::GetForProfile(profile())
2447 ->FlushMojoCallsForTesting();
2448
2449 // Set policy to pin the web app.
2450 base::DictionaryValue entry;
2451 entry.SetKey(kPinnedAppsPrefAppIDKey, base::Value(app_url.spec()));
2452 base::ListValue policy_value;
2453 policy_value.Append(std::move(entry));
2454 profile()->GetPrefs()->Set(prefs::kPolicyPinnedLauncherApps, policy_value);
2455
2456 // Check web app is pinned and fixed.
2457 EXPECT_EQ(shelf_model()->item_count(), 2);
2458 EXPECT_EQ(shelf_model()->items()[0].type, ash::TYPE_BROWSER_SHORTCUT);
2459 EXPECT_EQ(shelf_model()->items()[1].type, ash::TYPE_PINNED_APP);
2460 EXPECT_EQ(shelf_model()->items()[1].id.app_id, app_id);
2461 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
2462 GetPinnableForAppID(app_id, profile()));
2463 }
2464
IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest,WebAppPolicyNonExistentApp)2465 IN_PROC_BROWSER_TEST_F(ShelfWebAppBrowserTest, WebAppPolicyNonExistentApp) {
2466 // Don't install the web app.
2467 GURL app_url = GURL("https://example.org/");
2468 web_app::AppId app_id = web_app::GenerateAppIdFromURL(app_url);
2469
2470 // Set policy to pin the non existent web app.
2471 base::DictionaryValue entry;
2472 entry.SetKey(kPinnedAppsPrefAppIDKey, base::Value(app_url.spec()));
2473 base::ListValue policy_value;
2474 policy_value.Append(std::move(entry));
2475 profile()->GetPrefs()->Set(prefs::kPolicyPinnedLauncherApps, policy_value);
2476
2477 // Check web app policy is ignored.
2478 EXPECT_EQ(shelf_model()->item_count(), 1);
2479 EXPECT_EQ(shelf_model()->items()[0].type, ash::TYPE_BROWSER_SHORTCUT);
2480 EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
2481 GetPinnableForAppID(app_id, profile()));
2482 }
2483
2484 // Test that "Close" is shown in the context menu when there are opened browsers
2485 // windows.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,ShelfContextMenuVerifyCloseItemAppearance)2486 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,
2487 ShelfContextMenuVerifyCloseItemAppearance) {
2488 // Open a context menu for the existing browser window.
2489 std::unique_ptr<ShelfContextMenu> menu1 = CreateBrowserItemContextMenu();
2490 // Check if "Close" is added to in the context menu.
2491 ASSERT_TRUE(IsItemPresentInMenu(menu1.get(), ash::MENU_CLOSE));
2492
2493 // Close all windows via the menu item.
2494 CloseBrowserWindow(browser(), menu1.get(), ash::MENU_CLOSE);
2495 EXPECT_EQ(0u, BrowserList::GetInstance()->size());
2496
2497 // Check if "Close" is removed from the context menu.
2498 std::unique_ptr<ShelfContextMenu> menu2 = CreateBrowserItemContextMenu();
2499 ASSERT_FALSE(IsItemPresentInMenu(menu2.get(), ash::MENU_CLOSE));
2500 }
2501
2502 // Chrome's ShelfModel should have the browser item and delegate.
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest,ShelfModelInitialization)2503 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, ShelfModelInitialization) {
2504 EXPECT_EQ(1, shelf_model()->item_count());
2505 EXPECT_EQ(extension_misc::kChromeAppId, shelf_model()->items()[0].id.app_id);
2506 EXPECT_TRUE(
2507 shelf_model()->GetShelfItemDelegate(shelf_model()->items()[0].id));
2508 }
2509
2510 class HotseatShelfAppBrowserTest : public ShelfAppBrowserTest {
2511 public:
2512 HotseatShelfAppBrowserTest() = default;
2513 HotseatShelfAppBrowserTest(const HotseatShelfAppBrowserTest&) = delete;
2514 HotseatShelfAppBrowserTest& operator=(const HotseatShelfAppBrowserTest&) =
2515 delete;
2516 ~HotseatShelfAppBrowserTest() override = default;
2517
2518 // ShelfAppBrowserTest:
SetUp()2519 void SetUp() override {
2520 // Disable contextual nudges to prevent in-app to home nudge from being
2521 // announced in the ChromeVox test.
2522 scoped_feature_list_.InitAndDisableFeature(
2523 ash::features::kContextualNudges);
2524 ShelfAppBrowserTest::SetUp();
2525 }
2526
2527 private:
2528 base::test::ScopedFeatureList scoped_feature_list_;
2529 };
2530
2531 // Verifies that hotseat should be hidden after launching the browser from
2532 // a context menu (https://crbug.com/1072043).
IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest,LaunchAppFromContextMenu)2533 IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest, LaunchAppFromContextMenu) {
2534 ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
2535
2536 ash::RootWindowController* controller =
2537 ash::Shell::GetRootWindowControllerWithDisplayId(
2538 display::Screen::GetScreen()->GetPrimaryDisplay().id());
2539 ash::ShelfView* shelf_view = controller->shelf()->GetShelfViewForTesting();
2540
2541 ash::ShelfModel* model = shelf_view->model();
2542 EXPECT_EQ(1, model->item_count());
2543
2544 ExtendHotseat(browser());
2545
2546 const ash::ShelfID browser_icon_id = model->items()[0].id;
2547 views::View* browser_icon = shelf_view->GetShelfAppButton(browser_icon_id);
2548
2549 ash::ShelfViewTestAPI test_api(shelf_view);
2550 base::RunLoop run_loop;
2551 test_api.SetShelfContextMenuCallback(run_loop.QuitClosure());
2552
2553 ui::test::EventGenerator event_generator(controller->GetRootWindow());
2554 event_generator.MoveMouseTo(browser_icon->GetBoundsInScreen().CenterPoint());
2555 event_generator.PressRightButton();
2556
2557 // Wait until the context menu shows.
2558 run_loop.Run();
2559
2560 ash::ShelfMenuModelAdapter* shelf_menu_model_adapter =
2561 shelf_view->shelf_menu_model_adapter_for_testing();
2562 ASSERT_TRUE(shelf_menu_model_adapter->IsShowingMenu());
2563
2564 // Click at the menu item whose command is ash::MENU_NEW_WINDOW.
2565 event_generator.MoveMouseTo(shelf_menu_model_adapter->root_for_testing()
2566 ->GetMenuItemByID(ash::MENU_NEW_WINDOW)
2567 ->GetBoundsInScreen()
2568 .CenterPoint());
2569 event_generator.ClickLeftButton();
2570
2571 // Verify that hotseat is hidden.
2572 EXPECT_EQ(ash::HotseatState::kHidden,
2573 controller->shelf()->shelf_layout_manager()->hotseat_state());
2574 }
2575
2576 // Tests that launching and switching apps by tapping shelf buttons hides the
2577 // hotseat.
IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest,TappingAppIconsHidesHotseat)2578 IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest,
2579 TappingAppIconsHidesHotseat) {
2580 ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
2581
2582 // Create two apps, then extend the hotseat.
2583 ash::ShelfID shortcut_id_1 = CreateShortcut("app1");
2584 ash::ShelfID shortcut_id_2 = CreateShortcut("app2");
2585 ExtendHotseat(browser());
2586
2587 // Launch app1, the hotseat should hide.
2588 ash::RootWindowController* controller =
2589 ash::Shell::GetRootWindowControllerWithDisplayId(
2590 display::Screen::GetScreen()->GetPrimaryDisplay().id());
2591 ash::ShelfView* shelf_view = controller->shelf()->GetShelfViewForTesting();
2592 views::View* button_1 = shelf_view->GetShelfAppButton(shortcut_id_1);
2593 ui::test::EventGenerator event_generator(controller->GetRootWindow());
2594 event_generator.GestureTapAt(button_1->GetBoundsInScreen().CenterPoint());
2595
2596 EXPECT_EQ(ash::HotseatState::kHidden,
2597 controller->shelf()->shelf_layout_manager()->hotseat_state());
2598
2599 // Show the hotseat again, and launch app2. The hotseat should hide again.
2600 ExtendHotseat(browser());
2601 views::View* button_2 = shelf_view->GetShelfAppButton(shortcut_id_2);
2602 event_generator.GestureTapAt(button_2->GetBoundsInScreen().CenterPoint());
2603
2604 EXPECT_EQ(ash::HotseatState::kHidden,
2605 controller->shelf()->shelf_layout_manager()->hotseat_state());
2606
2607 // Extend the hotseat and test that switching back to app1 results in a hidden
2608 // hotseat.
2609 ExtendHotseat(browser());
2610 event_generator.GestureTapAt(button_1->GetBoundsInScreen().CenterPoint());
2611 EXPECT_EQ(ash::HotseatState::kHidden,
2612 controller->shelf()->shelf_layout_manager()->hotseat_state());
2613 }
2614
2615 // Verify that the in-app shelf should be shown when the app icon receives
2616 // the accessibility focus.
IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest,EnableChromeVox)2617 IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest, EnableChromeVox) {
2618 ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
2619 chromeos::SpeechMonitor speech_monitor;
2620
2621 // Enable ChromeVox.
2622 ASSERT_FALSE(
2623 chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
2624 chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(true);
2625
2626 // Wait for ChromeVox to start reading anything.
2627 speech_monitor.ExpectSpeechPattern("*");
2628 speech_monitor.Call([this]() {
2629 // Disable earcons (https://crbug.com/396507).
2630 const std::string script("ChromeVox.earcons.playEarcon = function() {};");
2631 extensions::ExtensionHost* host =
2632 extensions::ProcessManager::Get(browser()->profile())
2633 ->GetBackgroundHostForExtension(
2634 extension_misc::kChromeVoxExtensionId);
2635 content::ExecuteScriptAsync(host->host_contents(), script);
2636 });
2637
2638 views::View* home_button = ash::ShelfTestApi().GetHomeButton();
2639 speech_monitor.Call([home_button]() {
2640 // Send hover accessibility event - ChromeVox needs this event to properly
2641 // recognize the home button as the node with accessibility focus during
2642 // touch exploration. The event is generally sent on tap, but with a delay,
2643 // so relying on tap event only may introduce test flakiness.
2644 home_button->NotifyAccessibilityEvent(ax::mojom::Event::kHover, true);
2645 });
2646
2647 speech_monitor.ExpectSpeech("Launcher");
2648 speech_monitor.ExpectSpeech("Button");
2649 speech_monitor.ExpectSpeech("Shelf");
2650 speech_monitor.ExpectSpeech("Tool bar");
2651 speech_monitor.ExpectSpeech(", window");
2652
2653 ash::RootWindowController* controller =
2654 ash::Shell::GetRootWindowControllerWithDisplayId(
2655 display::Screen::GetScreen()->GetPrimaryDisplay().id());
2656 speech_monitor.Call([controller]() {
2657 // Hotseat is expected to be extended if spoken feedback is enabled.
2658 ASSERT_EQ(ash::HotseatState::kExtended,
2659 controller->shelf()->shelf_layout_manager()->hotseat_state());
2660 });
2661
2662 ui::test::EventGenerator event_generator(controller->GetRootWindow());
2663 auto* generator_ptr = &event_generator;
2664
2665 speech_monitor.Call([generator_ptr]() {
2666 // Press the search + right. Expects that the browser icon receives the
2667 // accessibility focus and the hotseat remains in kExtended state.
2668 generator_ptr->PressKey(ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN);
2669 });
2670
2671 const int browser_index =
2672 ash::ShelfModel::Get()->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
2673 speech_monitor.ExpectSpeech(
2674 base::UTF16ToASCII(ash::ShelfModel::Get()->items()[browser_index].title));
2675 speech_monitor.Replay();
2676
2677 EXPECT_EQ(ash::HotseatState::kExtended,
2678 controller->shelf()->shelf_layout_manager()->hotseat_state());
2679
2680 // Click on the home button. Expects that the hotseat is shown in
2681 // kShownHomeLauncher state. Note that the home button should be shown in
2682 // tablet mode with spoken feedback enabled.
2683 event_generator.MoveMouseTo(home_button->GetBoundsInScreen().CenterPoint());
2684 event_generator.ClickLeftButton();
2685
2686 EXPECT_EQ(ash::HotseatState::kShownHomeLauncher,
2687 controller->shelf()->shelf_layout_manager()->hotseat_state());
2688 }
2689
2690 using ShelfAppBrowserTestWithDesks = ShelfAppBrowserTest;
2691
IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestWithDesks,MultipleDesks)2692 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestWithDesks, MultipleDesks) {
2693 auto* desks_controller = ash::DesksController::Get();
2694 desks_controller->NewDesk(ash::DesksCreationRemovalSource::kButton);
2695
2696 // Tests starts with an existing browser on desk_1.
2697 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
2698
2699 // Activate desk_2 and click on the browser's icon on the shelf while being on
2700 // that desk. This should not switch back to desk_1, but rather create a new
2701 // browser window.
2702 ASSERT_EQ(2u, desks_controller->desks().size());
2703 auto* desk_2 = desks_controller->desks()[1].get();
2704 ash::ActivateDesk(desk_2);
2705
2706 const int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
2707 ash::ShelfID browser_id = shelf_model()->items()[browser_index].id;
2708
2709 SelectItemAndFlushMojoCallsForAppService(browser_id);
2710 EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
2711 EXPECT_FALSE(desks_controller->AreDesksBeingModified());
2712 EXPECT_TRUE(desk_2->is_active());
2713
2714 // The shelf context menu should show 2 items for both browsers. No new items
2715 // should be created and existing window should not be minimized.
2716 EXPECT_EQ(ash::ShelfAction::SHELF_ACTION_NONE,
2717 SelectItemAndFlushMojoCallsForAppService(
2718 browser_id, ui::ET_MOUSE_PRESSED, display::kInvalidDisplayId,
2719 ash::LAUNCH_FROM_SHELF));
2720 EXPECT_EQ(
2721 2u, controller_
2722 ->GetAppMenuItemsForTesting(shelf_model()->items()[browser_index])
2723 .size());
2724 }
2725
2726 class PerDeskShelfAppBrowserTest : public ShelfAppBrowserTest,
2727 public ::testing::WithParamInterface<bool> {
2728 public:
2729 PerDeskShelfAppBrowserTest() = default;
2730 PerDeskShelfAppBrowserTest(const PerDeskShelfAppBrowserTest&) = delete;
2731 PerDeskShelfAppBrowserTest& operator=(const PerDeskShelfAppBrowserTest&) =
2732 delete;
2733 ~PerDeskShelfAppBrowserTest() override = default;
2734
shelf_view() const2735 ash::ShelfView* shelf_view() const { return shelf_view_; }
2736
2737 // ShelfAppBrowserTest:
SetUp()2738 void SetUp() override {
2739 if (GetParam()) {
2740 scoped_feature_list_.InitAndEnableFeature(ash::features::kPerDeskShelf);
2741 } else {
2742 scoped_feature_list_.InitAndDisableFeature(ash::features::kPerDeskShelf);
2743 }
2744
2745 ShelfAppBrowserTest::SetUp();
2746 }
2747
SetUpOnMainThread()2748 void SetUpOnMainThread() override {
2749 ShelfAppBrowserTest::SetUpOnMainThread();
2750 shelf_view_ = ash::Shell::GetPrimaryRootWindowController()
2751 ->shelf()
2752 ->GetShelfViewForTesting();
2753 // Start tests with 2 desks.
2754 ash::DesksController::Get()->NewDesk(
2755 ash::DesksCreationRemovalSource::kButton);
2756 ash::ShelfViewTestAPI test_api(shelf_view());
2757 test_api.SetShelfContextMenuCallback(base::BindRepeating(
2758 &PerDeskShelfAppBrowserTest::OnAppMenuShown, base::Unretained(this)));
2759 }
2760
CreateTestBrowser()2761 void CreateTestBrowser() {
2762 Browser* new_browser = CreateBrowser(browser()->profile());
2763 new_browser->window()->Show();
2764 new_browser->window()->Activate();
2765 }
2766
GetBrowserId() const2767 ash::ShelfID GetBrowserId() const {
2768 const int browser_index =
2769 GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
2770 return shelf_model()->items()[browser_index].id;
2771 }
2772
ClickBrowserShelfButtonAndGetMenu()2773 ash::ShelfMenuModelAdapter* ClickBrowserShelfButtonAndGetMenu() {
2774 views::View* browser_icon = shelf_view()->GetShelfAppButton(GetBrowserId());
2775 run_loop_ = std::make_unique<base::RunLoop>();
2776 ui::test::EventGenerator event_generator(
2777 ash::Shell::GetPrimaryRootWindow());
2778 event_generator.MoveMouseTo(
2779 browser_icon->GetBoundsInScreen().CenterPoint());
2780 event_generator.ClickLeftButton();
2781 run_loop_->Run();
2782 ash::ShelfMenuModelAdapter* shelf_menu_model_adapter =
2783 shelf_view()->shelf_menu_model_adapter_for_testing();
2784 EXPECT_TRUE(shelf_menu_model_adapter);
2785 EXPECT_TRUE(shelf_menu_model_adapter->IsShowingMenu());
2786 return shelf_menu_model_adapter;
2787 }
2788
2789 private:
OnAppMenuShown()2790 void OnAppMenuShown() {
2791 if (run_loop_)
2792 std::move(run_loop_)->Quit();
2793 }
2794
2795 ash::ShelfView* shelf_view_ = nullptr;
2796 std::unique_ptr<base::RunLoop> run_loop_;
2797 base::test::ScopedFeatureList scoped_feature_list_;
2798 };
2799
IN_PROC_BROWSER_TEST_P(PerDeskShelfAppBrowserTest,AppMenus)2800 IN_PROC_BROWSER_TEST_P(PerDeskShelfAppBrowserTest, AppMenus) {
2801 // On desk_1, create 3 browsers. Note that the test starts with a default
2802 // browser.
2803 CreateTestBrowser();
2804 CreateTestBrowser();
2805 EXPECT_EQ(3u, chrome::GetTotalBrowserCount());
2806
2807 // Switch to desk_2, and create 2 more browsers.
2808 auto* desks_controller = ash::DesksController::Get();
2809 auto* desk_2 = desks_controller->desks()[1].get();
2810 ash::ActivateDesk(desk_2);
2811 CreateTestBrowser();
2812 CreateTestBrowser();
2813 EXPECT_EQ(5u, chrome::GetTotalBrowserCount());
2814
2815 // Click on the Browser icon on the shelf and expect the app items menu will
2816 // show, and the number of items in the menu will depend on whether the
2817 // per-desk shelf feature is enabled or not.
2818 auto* model_adapter = ClickBrowserShelfButtonAndGetMenu();
2819 const bool is_per_desk_shelf_enabled = GetParam();
2820 constexpr int kTitleAndSeparatorCount = 2;
2821 if (is_per_desk_shelf_enabled) {
2822 EXPECT_EQ(2 + kTitleAndSeparatorCount,
2823 model_adapter->model()->GetItemCount());
2824 } else {
2825 EXPECT_EQ(5 + kTitleAndSeparatorCount,
2826 model_adapter->model()->GetItemCount());
2827 }
2828
2829 // Switch to desk_1, and verify the app items count again.
2830 auto* desk_1 = desks_controller->desks()[0].get();
2831 ash::ActivateDesk(desk_1);
2832 model_adapter = ClickBrowserShelfButtonAndGetMenu();
2833 if (is_per_desk_shelf_enabled) {
2834 EXPECT_EQ(3 + kTitleAndSeparatorCount,
2835 model_adapter->model()->GetItemCount());
2836 } else {
2837 EXPECT_EQ(5 + kTitleAndSeparatorCount,
2838 model_adapter->model()->GetItemCount());
2839 }
2840 }
2841
2842 INSTANTIATE_TEST_SUITE_P(All, PerDeskShelfAppBrowserTest, ::testing::Bool());
2843