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