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 
9 #include <algorithm>
10 #include <map>
11 #include <memory>
12 #include <set>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "ash/display/display_configuration_controller.h"
18 #include "ash/multi_user/multi_user_window_manager_impl.h"
19 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
20 #include "ash/public/cpp/multi_user_window_manager.h"
21 #include "ash/public/cpp/shelf_item.h"
22 #include "ash/public/cpp/shelf_item_delegate.h"
23 #include "ash/public/cpp/shelf_model.h"
24 #include "ash/public/cpp/shelf_types.h"
25 #include "ash/public/cpp/window_properties.h"
26 #include "ash/shelf/shelf_application_menu_model.h"
27 #include "base/callback_helpers.h"
28 #include "base/command_line.h"
29 #include "base/compiler_specific.h"
30 #include "base/feature_list.h"
31 #include "base/files/file_path.h"
32 #include "base/json/json_string_value_serializer.h"
33 #include "base/location.h"
34 #include "base/memory/ptr_util.h"
35 #include "base/metrics/histogram.h"
36 #include "base/metrics/statistics_recorder.h"
37 #include "base/run_loop.h"
38 #include "base/single_thread_task_runner.h"
39 #include "base/strings/utf_string_conversions.h"
40 #include "base/test/scoped_feature_list.h"
41 #include "base/values.h"
42 #include "build/build_config.h"
43 #include "chrome/browser/apps/app_service/app_service_proxy.h"
44 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
45 #include "chrome/browser/apps/app_service/app_service_test.h"
46 #include "chrome/browser/chromeos/arc/arc_util.h"
47 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
48 #include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
49 #include "chrome/browser/chromeos/crostini/crostini_util.h"
50 #include "chrome/browser/chromeos/file_manager/app_id.h"
51 #include "chrome/browser/chromeos/login/demo_mode/demo_mode_test_helper.h"
52 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
53 #include "chrome/browser/chromeos/profiles/profile_helper.h"
54 #include "chrome/browser/extensions/extension_service.h"
55 #include "chrome/browser/extensions/test_extension_system.h"
56 #include "chrome/browser/prefs/browser_prefs.h"
57 #include "chrome/browser/sync/profile_sync_service_factory.h"
58 #include "chrome/browser/ui/app_icon_loader.h"
59 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
60 #include "chrome/browser/ui/app_list/arc/arc_app_icon.h"
61 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
62 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
63 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
64 #include "chrome/browser/ui/app_list/arc/arc_default_app_list.h"
65 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
66 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
67 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
68 #include "chrome/browser/ui/ash/launcher/app_service/app_service_app_window_launcher_item_controller.h"
69 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
70 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
71 #include "chrome/browser/ui/ash/launcher/arc_app_window.h"
72 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
73 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
74 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h"
75 #include "chrome/browser/ui/ash/launcher/shelf_spinner_controller.h"
76 #include "chrome/browser/ui/ash/launcher/shelf_spinner_item_controller.h"
77 #include "chrome/browser/ui/ash/multi_user/multi_profile_support.h"
78 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
79 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
80 #include "chrome/browser/ui/ash/session_controller_client_impl.h"
81 #include "chrome/browser/ui/ash/test_wallpaper_controller.h"
82 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
83 #include "chrome/browser/ui/browser.h"
84 #include "chrome/browser/ui/browser_commands.h"
85 #include "chrome/browser/ui/browser_finder.h"
86 #include "chrome/browser/ui/browser_list.h"
87 #include "chrome/browser/ui/browser_tabstrip.h"
88 #include "chrome/browser/ui/tabs/tab_strip_model.h"
89 #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h"
90 #include "chrome/browser/web_applications/components/policy/web_app_policy_constants.h"
91 #include "chrome/browser/web_applications/components/web_app_constants.h"
92 #include "chrome/browser/web_applications/test/test_system_web_app_manager.h"
93 #include "chrome/browser/web_applications/test/test_web_app_provider.h"
94 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
95 #include "chrome/common/chrome_constants.h"
96 #include "chrome/common/chrome_features.h"
97 #include "chrome/common/chrome_switches.h"
98 #include "chrome/common/extensions/extension_constants.h"
99 #include "chrome/common/pref_names.h"
100 #include "chrome/test/base/browser_with_test_window_test.h"
101 #include "chrome/test/base/test_browser_window_aura.h"
102 #include "chrome/test/base/testing_profile.h"
103 #include "chrome/test/base/testing_profile_manager.h"
104 #include "chromeos/constants/chromeos_features.h"
105 #include "chromeos/constants/chromeos_switches.h"
106 #include "components/account_id/account_id.h"
107 #include "components/arc/arc_prefs.h"
108 #include "components/arc/arc_util.h"
109 #include "components/arc/metrics/arc_metrics_constants.h"
110 #include "components/arc/mojom/app.mojom.h"
111 #include "components/arc/test/fake_app_instance.h"
112 #include "components/exo/shell_surface_util.h"
113 #include "components/keep_alive_registry/scoped_keep_alive.h"
114 #include "components/prefs/pref_notifier_impl.h"
115 #include "components/sync/base/model_type.h"
116 #include "components/sync/driver/sync_service.h"
117 #include "components/sync/driver/sync_user_settings.h"
118 #include "components/sync/protocol/sync.pb.h"
119 #include "components/sync/test/model/fake_sync_change_processor.h"
120 #include "components/sync/test/model/sync_error_factory_mock.h"
121 #include "components/sync_preferences/pref_model_associator.h"
122 #include "components/sync_preferences/testing_pref_service_syncable.h"
123 #include "components/user_manager/fake_user_manager.h"
124 #include "components/user_manager/scoped_user_manager.h"
125 #include "content/public/browser/web_contents.h"
126 #include "content/public/browser/web_contents_observer.h"
127 #include "content/public/test/test_utils.h"
128 #include "content/public/test/web_contents_tester.h"
129 #include "extensions/browser/app_window/app_window_contents.h"
130 #include "extensions/browser/app_window/app_window_registry.h"
131 #include "extensions/browser/app_window/native_app_window.h"
132 #include "extensions/browser/extension_registry.h"
133 #include "extensions/common/constants.h"
134 #include "extensions/common/extension.h"
135 #include "extensions/common/manifest_constants.h"
136 #include "extensions/grit/extensions_browser_resources.h"
137 #include "services/network/test/test_network_connection_tracker.h"
138 #include "testing/gtest/include/gtest/gtest.h"
139 #include "ui/aura/client/window_parenting_client.h"
140 #include "ui/aura/window.h"
141 #include "ui/base/models/menu_model.h"
142 #include "ui/base/resource/resource_bundle.h"
143 #include "ui/base/ui_base_features.h"
144 #include "ui/display/display.h"
145 #include "ui/display/display_switches.h"
146 #include "ui/display/screen.h"
147 #include "ui/events/base_event_utils.h"
148 #include "ui/events/event_constants.h"
149 #include "ui/events/types/event_type.h"
150 #include "ui/gfx/image/image_skia_operations.h"
151 #include "ui/gfx/image/image_unittest_util.h"
152 #include "ui/views/widget/widget.h"
153 
154 using base::ASCIIToUTF16;
155 using extensions::Extension;
156 using extensions::Manifest;
157 using extensions::UnloadedExtensionReason;
158 
159 namespace {
160 constexpr char kOfflineGmailUrl[] = "https://mail.google.com/mail/mu/u";
161 constexpr char kGmailUrl[] = "https://mail.google.com/mail/u";
162 constexpr char kGmailLaunchURL[] = "https://mail.google.com/mail/ca";
163 constexpr char kLaunchURL[] = "https://foo.example/";
164 
165 // An extension prefix.
166 constexpr char kCrxAppPrefix[] = "_crx_";
167 
168 // Dummy app id is used to put at least one pin record to prevent initializing
169 // pin model with default apps that can affect some tests.
170 constexpr char kDummyAppId[] = "dummyappid_dummyappid_dummyappid";
171 
172 // Test implementation of AppIconLoader.
173 class TestAppIconLoaderImpl : public AppIconLoader {
174  public:
175   TestAppIconLoaderImpl() = default;
176   TestAppIconLoaderImpl(const TestAppIconLoaderImpl&) = delete;
177   TestAppIconLoaderImpl& operator=(const TestAppIconLoaderImpl&) = delete;
178   ~TestAppIconLoaderImpl() override = default;
179 
AddSupportedApp(const std::string & id)180   void AddSupportedApp(const std::string& id) { supported_apps_.insert(id); }
181 
182   // AppIconLoader implementation:
CanLoadImageForApp(const std::string & id)183   bool CanLoadImageForApp(const std::string& id) override {
184     return supported_apps_.find(id) != supported_apps_.end();
185   }
FetchImage(const std::string & id)186   void FetchImage(const std::string& id) override { ++fetch_count_; }
ClearImage(const std::string & id)187   void ClearImage(const std::string& id) override { ++clear_count_; }
UpdateImage(const std::string & id)188   void UpdateImage(const std::string& id) override {}
189 
fetch_count() const190   int fetch_count() const { return fetch_count_; }
clear_count() const191   int clear_count() const { return clear_count_; }
192 
193  private:
194   int fetch_count_ = 0;
195   int clear_count_ = 0;
196   std::set<std::string> supported_apps_;
197 };
198 
199 // Test implementation of LauncherControllerHelper.
200 class TestLauncherControllerHelper : public LauncherControllerHelper {
201  public:
TestLauncherControllerHelper()202   TestLauncherControllerHelper() : LauncherControllerHelper(nullptr) {}
TestLauncherControllerHelper(Profile * profile)203   explicit TestLauncherControllerHelper(Profile* profile)
204       : LauncherControllerHelper(profile) {}
205   TestLauncherControllerHelper(const TestLauncherControllerHelper&) = delete;
206   TestLauncherControllerHelper& operator=(const TestLauncherControllerHelper&) =
207       delete;
208   ~TestLauncherControllerHelper() override = default;
209 
210   // Sets the id for the specified tab.
SetAppID(content::WebContents * tab,const std::string & id)211   void SetAppID(content::WebContents* tab, const std::string& id) {
212     tab_id_map_[tab] = id;
213   }
214 
215   // Returns true if there is an id registered for |tab|.
HasAppID(content::WebContents * tab) const216   bool HasAppID(content::WebContents* tab) const {
217     return tab_id_map_.find(tab) != tab_id_map_.end();
218   }
219 
220   // LauncherControllerHelper:
GetAppID(content::WebContents * tab)221   std::string GetAppID(content::WebContents* tab) override {
222     return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab]
223                                                       : std::string();
224   }
225 
IsValidIDForCurrentUser(const std::string & id) const226   bool IsValidIDForCurrentUser(const std::string& id) const override {
227     for (TabToStringMap::const_iterator i = tab_id_map_.begin();
228          i != tab_id_map_.end(); ++i) {
229       if (i->second == id)
230         return true;
231     }
232     return false;
233   }
234 
GetArcAppListPrefs() const235   ArcAppListPrefs* GetArcAppListPrefs() const override { return nullptr; }
236 
237  private:
238   typedef std::map<content::WebContents*, std::string> TabToStringMap;
239 
240   TabToStringMap tab_id_map_;
241 };
242 
243 // Test implementation of a V2 app launcher item controller.
244 class TestV2AppLauncherItemController : public ash::ShelfItemDelegate {
245  public:
TestV2AppLauncherItemController(const std::string & app_id)246   explicit TestV2AppLauncherItemController(const std::string& app_id)
247       : ash::ShelfItemDelegate(ash::ShelfID(app_id)) {}
248 
249   TestV2AppLauncherItemController(const TestV2AppLauncherItemController&) =
250       delete;
251   TestV2AppLauncherItemController& operator=(
252       const TestV2AppLauncherItemController&) = delete;
253   ~TestV2AppLauncherItemController() override = default;
254 
255   // Override for ash::ShelfItemDelegate:
ItemSelected(std::unique_ptr<ui::Event> event,int64_t display_id,ash::ShelfLaunchSource source,ItemSelectedCallback callback,const ItemFilterPredicate & filter_predicate)256   void ItemSelected(std::unique_ptr<ui::Event> event,
257                     int64_t display_id,
258                     ash::ShelfLaunchSource source,
259                     ItemSelectedCallback callback,
260                     const ItemFilterPredicate& filter_predicate) override {
261     std::move(callback).Run(ash::SHELF_ACTION_WINDOW_ACTIVATED, {});
262   }
ExecuteCommand(bool,int64_t,int32_t,int64_t)263   void ExecuteCommand(bool, int64_t, int32_t, int64_t) override {}
Close()264   void Close() override {}
265 };
266 
267 // Simulates selection of the shelf item.
SelectItem(ash::ShelfItemDelegate * delegate)268 void SelectItem(ash::ShelfItemDelegate* delegate) {
269   std::unique_ptr<ui::Event> event = std::make_unique<ui::MouseEvent>(
270       ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
271       ui::EF_NONE, 0);
272   delegate->ItemSelected(std::move(event), display::kInvalidDisplayId,
273                          ash::LAUNCH_FROM_UNKNOWN, base::DoNothing(),
274                          base::NullCallback());
275 }
276 
IsWindowOnDesktopOfUser(aura::Window * window,const AccountId & account_id)277 bool IsWindowOnDesktopOfUser(aura::Window* window,
278                              const AccountId& account_id) {
279   return MultiUserWindowManagerHelper::GetInstance()->IsWindowOnDesktopOfUser(
280       window, account_id);
281 }
282 
283 }  // namespace
284 
285 class ChromeLauncherControllerTest : public BrowserWithTestWindowTest {
286  protected:
ChromeLauncherControllerTest()287   ChromeLauncherControllerTest()
288       : BrowserWithTestWindowTest(Browser::TYPE_NORMAL) {
289   }
290 
291   ChromeLauncherControllerTest(const ChromeLauncherControllerTest&) = delete;
292   ChromeLauncherControllerTest& operator=(const ChromeLauncherControllerTest&) =
293       delete;
294   ~ChromeLauncherControllerTest() override = default;
295 
SetUp()296   void SetUp() override {
297     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
298     command_line->AppendSwitch(switches::kUseFirstDisplayAsInternal);
299 
300     app_list::AppListSyncableServiceFactory::SetUseInTesting(true);
301 
302     BrowserWithTestWindowTest::SetUp();
303 
304     model_ = std::make_unique<ash::ShelfModel>();
305 
306     base::DictionaryValue manifest;
307     manifest.SetString(extensions::manifest_keys::kName,
308                        "launcher controller test extension");
309     manifest.SetString(extensions::manifest_keys::kVersion, "1");
310     manifest.SetInteger(extensions::manifest_keys::kManifestVersion, 2);
311     manifest.SetString(extensions::manifest_keys::kDescription,
312                        "for testing pinned apps");
313     // AppService checks the app's type. So set the
314     // manifest_keys::kLaunchWebURL, so that the extension can get the type
315     // from manifest value, and then AppService can get the extension's type.
316     manifest.SetString(extensions::manifest_keys::kLaunchWebURL, kLaunchURL);
317 
318     base::DictionaryValue manifest_platform_app;
319     manifest_platform_app.SetString(extensions::manifest_keys::kName,
320                                     "launcher controller test platform app");
321     manifest_platform_app.SetString(extensions::manifest_keys::kVersion, "1");
322     manifest_platform_app.SetString(extensions::manifest_keys::kDescription,
323                                     "for testing pinned platform apps");
324     manifest_platform_app.SetString(extensions::manifest_keys::kApp, "true");
325     manifest_platform_app.Set(extensions::manifest_keys::kPlatformAppBackground,
326                               std::make_unique<base::DictionaryValue>());
327     auto scripts = std::make_unique<base::ListValue>();
328     scripts->AppendString("main.js");
329     manifest_platform_app.Set(
330         extensions::manifest_keys::kPlatformAppBackgroundScripts,
331         std::move(scripts));
332 
333     extensions::TestExtensionSystem* extension_system(
334         static_cast<extensions::TestExtensionSystem*>(
335             extensions::ExtensionSystem::Get(profile())));
336     extension_service_ = extension_system->CreateExtensionService(
337         base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
338     extension_service_->Init();
339 
340     DCHECK(profile());
341     extension_registry_ = extensions::ExtensionRegistry::Get(profile());
342     app_service_test_.SetUp(profile());
343 
344     if (auto_start_arc_test_)
345       arc_test_.SetUp(profile());
346 
347     // Wait until |extension_system| is signaled as started.
348     base::RunLoop run_loop;
349     extension_system->ready().Post(FROM_HERE, run_loop.QuitClosure());
350     run_loop.Run();
351 
352     // Many pinned app tests assume OS sync is enabled.
353     if (chromeos::features::IsSplitSettingsSyncEnabled()) {
354       syncer::SyncService* sync_service =
355           ProfileSyncServiceFactory::GetForProfile(profile());
356       sync_service->GetUserSettings()->SetOsSyncFeatureEnabled(true);
357     }
358 
359     app_list_syncable_service_ =
360         app_list::AppListSyncableServiceFactory::GetForProfile(profile());
361     StartAppSyncService(app_list_syncable_service_->GetAllSyncDataForTesting());
362 
363     std::string error;
364     extension_chrome_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
365                                           manifest, Extension::NO_FLAGS,
366                                           extension_misc::kChromeAppId, &error);
367     extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
368                                     manifest, Extension::NO_FLAGS,
369                                     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &error);
370     extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
371                                     manifest, Extension::NO_FLAGS,
372                                     "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", &error);
373     extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
374                                     manifest, Extension::NO_FLAGS,
375                                     "cccccccccccccccccccccccccccccccc", &error);
376     extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
377                                     manifest, Extension::NO_FLAGS,
378                                     "dddddddddddddddddddddddddddddddd", &error);
379     extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
380                                     manifest, Extension::NO_FLAGS,
381                                     "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", &error);
382     extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
383                                     manifest, Extension::NO_FLAGS,
384                                     "ffffffffffffffffffffffffffffffff", &error);
385     extension_platform_app_ = Extension::Create(
386         base::FilePath(), Manifest::UNPACKED, manifest_platform_app,
387         Extension::NO_FLAGS, "gggggggggggggggggggggggggggggggg", &error);
388     arc_support_host_ =
389         Extension::Create(base::FilePath(), Manifest::UNPACKED, manifest,
390                           Extension::NO_FLAGS, arc::kPlayStoreAppId, &error);
391     extension_service_->AddExtension(extension_chrome_.get());
392 
393     // Fake Gmail app.
394     base::DictionaryValue manifest_gmail;
395     manifest_gmail.SetString(extensions::manifest_keys::kName,
396                              "Gmail launcher controller test extension");
397     manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1");
398     manifest_gmail.SetInteger(extensions::manifest_keys::kManifestVersion, 2);
399     manifest_gmail.SetString(extensions::manifest_keys::kDescription,
400                              "for testing pinned Gmail");
401     manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL,
402                              kGmailLaunchURL);
403     auto list = std::make_unique<base::ListValue>();
404     list->AppendString("*://mail.google.com/mail/ca");
405     manifest_gmail.Set(extensions::manifest_keys::kWebURLs, std::move(list));
406 
407     extension_gmail_app_ = Extension::Create(
408         base::FilePath(), Manifest::UNPACKED, manifest_gmail,
409         Extension::NO_FLAGS, extension_misc::kGmailAppId, &error);
410     // Fake Google Doc app.
411     extension_doc_app_ = Extension::Create(
412         base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
413         extension_misc::kGoogleDocAppId, &error);
414 
415     // Fake Youtube app.
416     extension_youtube_app_ = Extension::Create(
417         base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
418         extension_misc::kYoutubeAppId, &error);
419 
420     // Fake File Manager app.
421     extension_files_app_ = Extension::Create(
422         base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
423         extension_misc::kFilesManagerAppId, &error);
424 
425     MaybeStartWebAppProvider();
426   }
427 
MaybeStartWebAppProvider()428   virtual void MaybeStartWebAppProvider() {
429     web_app::TestWebAppProvider::Get(profile())->Start();
430   }
431 
GetLastActiveWindowForItemController(AppWindowLauncherItemController * item_controller)432   ui::BaseWindow* GetLastActiveWindowForItemController(
433       AppWindowLauncherItemController* item_controller) {
434     return item_controller->last_active_window_;
435   }
436 
437   // Creates a running platform V2 app (not pinned) of type |app_id|.
CreateRunningV2App(const std::string & app_id)438   virtual void CreateRunningV2App(const std::string& app_id) {
439     DCHECK(!test_controller_);
440     // Change the created launcher controller into a V2 app controller.
441     std::unique_ptr<TestV2AppLauncherItemController> controller =
442         std::make_unique<TestV2AppLauncherItemController>(app_id);
443     test_controller_ = controller.get();
444     ash::ShelfID id = launcher_controller_->InsertAppLauncherItem(
445         std::move(controller), ash::STATUS_RUNNING, model_->item_count(),
446         ash::TYPE_APP);
447     DCHECK(launcher_controller_->IsPlatformApp(id));
448   }
449 
450   // Sets the stage for a multi user test.
SetUpMultiUserScenario(syncer::SyncChangeList * user_a,syncer::SyncChangeList * user_b)451   virtual void SetUpMultiUserScenario(syncer::SyncChangeList* user_a,
452                                       syncer::SyncChangeList* user_b) {
453     InitLauncherController();
454     EXPECT_EQ("Chrome", GetPinnedAppStatus());
455 
456     // Set an empty pinned pref to begin with.
457     syncer::SyncChangeList sync_list;
458     InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
459     SendPinChanges(sync_list, true);
460     EXPECT_EQ("Chrome", GetPinnedAppStatus());
461 
462     // Assume all applications have been added already.
463     extension_service_->AddExtension(extension1_.get());
464     extension_service_->AddExtension(extension2_.get());
465     extension_service_->AddExtension(extension_gmail_app_.get());
466     extension_service_->AddExtension(extension_doc_app_.get());
467     extension_service_->AddExtension(extension5_.get());
468     extension_service_->AddExtension(extension6_.get());
469     extension_service_->AddExtension(extension7_.get());
470     extension_service_->AddExtension(extension8_.get());
471     extension_service_->AddExtension(extension_platform_app_.get());
472     // There should be nothing in the list by now.
473     EXPECT_EQ("Chrome", GetPinnedAppStatus());
474 
475     // Set user a preferences.
476     InsertAddPinChange(user_a, 0, extension1_->id());
477     InsertAddPinChange(user_a, 1, extension2_->id());
478     InsertAddPinChange(user_a, 2, extension_gmail_app_->id());
479     InsertAddPinChange(user_a, 3, extension_platform_app_->id());
480     InsertAddPinChange(user_a, 4, extension_doc_app_->id());
481     InsertAddPinChange(user_a, 5, extension5_->id());
482     InsertAddPinChange(user_a, 6, extension_misc::kChromeAppId);
483 
484     // Set user b preferences.
485     InsertAddPinChange(user_b, 0, extension6_->id());
486     InsertAddPinChange(user_b, 1, extension7_->id());
487     InsertAddPinChange(user_b, 2, extension8_->id());
488     InsertAddPinChange(user_b, 3, extension_misc::kChromeAppId);
489   }
490 
TearDown()491   void TearDown() override {
492     arc_test_.TearDown();
493     launcher_controller_ = nullptr;
494     BrowserWithTestWindowTest::TearDown();
495     app_list::AppListSyncableServiceFactory::SetUseInTesting(false);
496   }
497 
CreateBrowserWindow()498   std::unique_ptr<BrowserWindow> CreateBrowserWindow() override {
499     return std::unique_ptr<TestBrowserWindow>(CreateTestBrowserWindowAura());
500   }
501 
CreateBrowserWithTestWindowForProfile(Profile * profile)502   std::unique_ptr<Browser> CreateBrowserWithTestWindowForProfile(
503       Profile* profile) {
504     TestBrowserWindow* browser_window = CreateTestBrowserWindowAura();
505     new TestBrowserWindowOwner(browser_window);
506     return CreateBrowser(profile, Browser::TYPE_NORMAL, false, browser_window);
507   }
508 
509   // Create an uninitialized chrome launcher controller instance.
CreateLauncherController()510   ChromeLauncherController* CreateLauncherController() {
511     launcher_controller_ =
512         std::make_unique<ChromeLauncherController>(profile(), model_.get());
513     return launcher_controller_.get();
514   }
515 
516   // Create and initialize the controller, owned by the test shell delegate.
InitLauncherController()517   void InitLauncherController() {
518     CreateLauncherController()->Init();
519     app_service_test_.FlushMojoCalls();
520   }
521 
522   // Create and initialize the controller; create a tab and show the browser.
InitLauncherControllerWithBrowser()523   void InitLauncherControllerWithBrowser() {
524     InitLauncherController();
525     chrome::NewTab(browser());
526     browser()->window()->Show();
527   }
528 
529   // Destroy the launcher controller instance and clear the local pointer.
ResetLauncherController()530   void ResetLauncherController() { launcher_controller_.reset(); }
531 
532   // Destroy and recreate the controller; clear and reinitialize the ShelfModel.
533   // Returns a pointer to the uninitialized controller, owned by shell delegate.
534   // TODO(msw): This does not accurately represent ChromeLauncherController
535   // lifetime or usage in production, and does not accurately simulate restarts.
RecreateLauncherController()536   ChromeLauncherController* RecreateLauncherController() {
537     // Destroy any existing controller first; only one may exist at a time.
538     ResetLauncherController();
539     model_ = std::make_unique<ash::ShelfModel>();
540     return CreateLauncherController();
541   }
542 
StartAppSyncService(const syncer::SyncDataList & init_sync_list)543   void StartAppSyncService(const syncer::SyncDataList& init_sync_list) {
544     app_list_syncable_service_->MergeDataAndStartSyncing(
545         syncer::APP_LIST, init_sync_list,
546         std::make_unique<syncer::FakeSyncChangeProcessor>(),
547         std::make_unique<syncer::SyncErrorFactoryMock>());
548     EXPECT_EQ(init_sync_list.size(),
549               app_list_syncable_service_->sync_items().size());
550   }
551 
StopAppSyncService()552   void StopAppSyncService() {
553     app_list_syncable_service_->StopSyncing(syncer::APP_LIST);
554   }
555 
556   // static
GetPreferencesModelType()557   syncer::ModelType GetPreferencesModelType() {
558     // SplitSettingsSync makes shelf prefs into OS prefs.
559     return chromeos::features::IsSplitSettingsSyncEnabled()
560                ? syncer::OS_PREFERENCES
561                : syncer::PREFERENCES;
562   }
563 
GetPrefSyncService()564   sync_preferences::PrefModelAssociator* GetPrefSyncService() {
565     sync_preferences::PrefServiceSyncable* pref_sync =
566         profile()->GetTestingPrefService();
567     sync_preferences::PrefModelAssociator* pref_sync_service =
568         static_cast<sync_preferences::PrefModelAssociator*>(
569             pref_sync->GetSyncableService(GetPreferencesModelType()));
570     return pref_sync_service;
571   }
572 
StartPrefSyncService(const syncer::SyncDataList & init_sync_list)573   void StartPrefSyncService(const syncer::SyncDataList& init_sync_list) {
574     base::Optional<syncer::ModelError> error =
575         GetPrefSyncService()->MergeDataAndStartSyncing(
576             GetPreferencesModelType(), init_sync_list,
577             std::make_unique<syncer::FakeSyncChangeProcessor>(),
578             std::make_unique<syncer::SyncErrorFactoryMock>());
579     EXPECT_FALSE(error.has_value());
580   }
581 
SetAppIconLoader(std::unique_ptr<AppIconLoader> loader)582   void SetAppIconLoader(std::unique_ptr<AppIconLoader> loader) {
583     std::vector<std::unique_ptr<AppIconLoader>> loaders;
584     loaders.push_back(std::move(loader));
585     launcher_controller_->SetAppIconLoadersForTest(loaders);
586   }
587 
SetAppIconLoaders(std::unique_ptr<AppIconLoader> loader1,std::unique_ptr<AppIconLoader> loader2)588   void SetAppIconLoaders(std::unique_ptr<AppIconLoader> loader1,
589                          std::unique_ptr<AppIconLoader> loader2) {
590     std::vector<std::unique_ptr<AppIconLoader>> loaders;
591     loaders.push_back(std::move(loader1));
592     loaders.push_back(std::move(loader2));
593     launcher_controller_->SetAppIconLoadersForTest(loaders);
594   }
595 
SetLauncherControllerHelper(LauncherControllerHelper * helper)596   void SetLauncherControllerHelper(LauncherControllerHelper* helper) {
597     launcher_controller_->SetLauncherControllerHelperForTest(
598         base::WrapUnique<LauncherControllerHelper>(helper));
599   }
600 
AppendPrefValue(base::ListValue * pref_value,const std::string & extension_id)601   void AppendPrefValue(base::ListValue* pref_value,
602                        const std::string& extension_id) {
603     base::DictionaryValue entry;
604     entry.SetKey(kPinnedAppsPrefAppIDKey, base::Value(extension_id));
605     pref_value->Append(std::move(entry));
606   }
607 
InsertRemoveAllPinsChange(syncer::SyncChangeList * list)608   void InsertRemoveAllPinsChange(syncer::SyncChangeList* list) {
609     for (const auto& sync_peer : app_list_syncable_service_->sync_items()) {
610       sync_pb::EntitySpecifics specifics;
611       sync_pb::AppListSpecifics* app_list_specifics =
612           specifics.mutable_app_list();
613       app_list_specifics->set_item_id(sync_peer.first);
614       app_list_specifics->set_item_type(sync_pb::AppListSpecifics::TYPE_APP);
615       syncer::SyncData sync_data =
616           syncer::SyncData::CreateLocalData(sync_peer.first, "Test", specifics);
617       list->push_back(syncer::SyncChange(
618           FROM_HERE, syncer::SyncChange::ACTION_DELETE, sync_data));
619     }
620   }
621 
GeneratePinPosition(int position)622   syncer::StringOrdinal GeneratePinPosition(int position) {
623     syncer::StringOrdinal ordinal_position =
624         syncer::StringOrdinal::CreateInitialOrdinal();
625     for (int i = 0; i < position; ++i)
626       ordinal_position = ordinal_position.CreateAfter();
627     return ordinal_position;
628   }
629 
InsertPinChange(syncer::SyncChangeList * list,int position,bool add_pin_change,const std::string & app_id,syncer::SyncChange::SyncChangeType type)630   void InsertPinChange(syncer::SyncChangeList* list,
631                        int position,
632                        bool add_pin_change,
633                        const std::string& app_id,
634                        syncer::SyncChange::SyncChangeType type) {
635     sync_pb::EntitySpecifics specifics;
636     sync_pb::AppListSpecifics* app_list_specifics =
637         specifics.mutable_app_list();
638     app_list_specifics->set_item_id(app_id);
639     app_list_specifics->set_item_type(sync_pb::AppListSpecifics::TYPE_APP);
640     if (add_pin_change) {
641       if (position >= 0) {
642         app_list_specifics->set_item_pin_ordinal(
643             GeneratePinPosition(position).ToInternalValue());
644       } else {
645         app_list_specifics->set_item_pin_ordinal(std::string());
646       }
647     }
648     syncer::SyncData sync_data =
649         syncer::SyncData::CreateLocalData(app_id, "Test", specifics);
650     list->push_back(syncer::SyncChange(FROM_HERE, type, sync_data));
651   }
652 
InsertAddPinChange(syncer::SyncChangeList * list,int position,const std::string & app_id)653   void InsertAddPinChange(syncer::SyncChangeList* list,
654                           int position,
655                           const std::string& app_id) {
656     InsertPinChange(list, position, true, app_id,
657                     syncer::SyncChange::ACTION_ADD);
658   }
659 
InsertUpdatePinChange(syncer::SyncChangeList * list,int position,const std::string & app_id)660   void InsertUpdatePinChange(syncer::SyncChangeList* list,
661                              int position,
662                              const std::string& app_id) {
663     InsertPinChange(list, position, true, app_id,
664                     syncer::SyncChange::ACTION_UPDATE);
665   }
666 
InsertRemovePinChange(syncer::SyncChangeList * list,const std::string & app_id)667   void InsertRemovePinChange(syncer::SyncChangeList* list,
668                              const std::string& app_id) {
669     InsertPinChange(list, -1, true, app_id, syncer::SyncChange::ACTION_UPDATE);
670   }
671 
InsertLegacyPinChange(syncer::SyncChangeList * list,const std::string & app_id)672   void InsertLegacyPinChange(syncer::SyncChangeList* list,
673                              const std::string& app_id) {
674     InsertPinChange(list, -1, false, app_id, syncer::SyncChange::ACTION_UPDATE);
675   }
676 
ResetPinModel()677   void ResetPinModel() {
678     syncer::SyncChangeList sync_list;
679     InsertRemoveAllPinsChange(&sync_list);
680     InsertAddPinChange(&sync_list, 0, kDummyAppId);
681     app_list_syncable_service_->ProcessSyncChanges(FROM_HERE, sync_list);
682   }
683 
SendPinChanges(const syncer::SyncChangeList & sync_list,bool reset_pin_model)684   void SendPinChanges(const syncer::SyncChangeList& sync_list,
685                       bool reset_pin_model) {
686     if (!reset_pin_model) {
687       app_list_syncable_service_->ProcessSyncChanges(FROM_HERE, sync_list);
688     } else {
689       syncer::SyncChangeList combined_sync_list;
690       InsertRemoveAllPinsChange(&combined_sync_list);
691       combined_sync_list.insert(combined_sync_list.end(), sync_list.begin(),
692                                 sync_list.end());
693       app_list_syncable_service_->ProcessSyncChanges(FROM_HERE,
694                                                      combined_sync_list);
695     }
696     content::RunAllTasksUntilIdle();
697   }
698 
699   // Set the index at which the chrome icon should be.
SetShelfChromeIconIndex(int index)700   void SetShelfChromeIconIndex(int index) {
701     DCHECK(
702         app_list_syncable_service_->GetPinPosition(extension_misc::kChromeAppId)
703             .IsValid());
704     syncer::StringOrdinal chrome_position;
705     chrome_position = index == 0 ? GeneratePinPosition(0).CreateBefore()
706                                  : GeneratePinPosition(index - 1).CreateBetween(
707                                        GeneratePinPosition(index));
708 
709     syncer::SyncChangeList sync_list;
710     sync_pb::EntitySpecifics specifics;
711     sync_pb::AppListSpecifics* app_list_specifics =
712         specifics.mutable_app_list();
713     app_list_specifics->set_item_id(extension_misc::kChromeAppId);
714     app_list_specifics->set_item_type(sync_pb::AppListSpecifics::TYPE_APP);
715     app_list_specifics->set_item_pin_ordinal(chrome_position.ToInternalValue());
716     syncer::SyncData sync_data = syncer::SyncData::CreateLocalData(
717         extension_misc::kChromeAppId, "Test", specifics);
718     sync_list.push_back(syncer::SyncChange(
719         FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
720     app_list_syncable_service_->ProcessSyncChanges(FROM_HERE, sync_list);
721   }
722 
723   // Gets the IDs of the currently pinned app items.
GetPinnedAppIds(ChromeLauncherController * controller,std::vector<std::string> * app_ids)724   void GetPinnedAppIds(ChromeLauncherController* controller,
725                        std::vector<std::string>* app_ids) {
726     app_ids->clear();
727     for (const auto& item : model_->items()) {
728       if (item.type == ash::TYPE_PINNED_APP)
729         app_ids->push_back(item.id.app_id);
730     }
731   }
732 
733   // Get the setup of the currently shown launcher items in one string.
734   // Each pinned element will start with a big letter, each running but not
735   // pinned V1 app will start with a small letter and each running but not
736   // pinned V2 app will start with a '*' + small letter.
GetPinnedAppStatus()737   std::string GetPinnedAppStatus() {
738     std::string result;
739     for (int i = 0; i < model_->item_count(); i++) {
740       if (!result.empty())
741         result.append(", ");
742       switch (model_->items()[i].type) {
743         case ash::TYPE_APP: {
744           if (launcher_controller_->IsPlatformApp(model_->items()[i].id))
745             result += "*";
746           const std::string& app = model_->items()[i].id.app_id;
747           EXPECT_FALSE(launcher_controller_->IsAppPinned(app));
748           if (app == extension1_->id()) {
749             result += "app1";
750           } else if (app == extension2_->id()) {
751             result += "app2";
752           } else if (app == extension5_->id()) {
753             result += "app5";
754           } else if (app == extension6_->id()) {
755             result += "app6";
756           } else if (app == extension7_->id()) {
757             result += "app7";
758           } else if (app == extension8_->id()) {
759             result += "app8";
760           } else if (app == extension_gmail_app_->id()) {
761             result += "gmail";
762           } else if (app == extension_platform_app_->id()) {
763             result += "platform_app";
764           } else if (app == extension_doc_app_->id()) {
765             result += "doc";
766           } else if (app == extension_youtube_app_->id()) {
767             result += "youtube";
768           } else {
769             result += app_service_test_.GetAppName(app);
770           }
771           break;
772         }
773         case ash::TYPE_PINNED_APP: {
774           if (launcher_controller_->IsPlatformApp(model_->items()[i].id))
775             result += "*";
776           const std::string& app = model_->items()[i].id.app_id;
777           EXPECT_TRUE(launcher_controller_->IsAppPinned(app));
778           if (app == extension1_->id()) {
779             result += "App1";
780           } else if (app == extension2_->id()) {
781             result += "App2";
782           } else if (app == extension5_->id()) {
783             result += "App5";
784           } else if (app == extension6_->id()) {
785             result += "App6";
786           } else if (app == extension7_->id()) {
787             result += "App7";
788           } else if (app == extension8_->id()) {
789             result += "App8";
790           } else if (app == extension_gmail_app_->id()) {
791             result += "Gmail";
792           } else if (app == extension_doc_app_->id()) {
793             result += "Doc";
794           } else if (app == extension_youtube_app_->id()) {
795             result += "Youtube";
796           } else if (app == extension_files_app_->id()) {
797             result += "Files";
798           } else if (app == extension_platform_app_->id()) {
799             result += "Platform_App";
800           } else if (app == arc_support_host_->id()) {
801             result += "Play Store";
802           } else if (app == crostini::kCrostiniTerminalSystemAppId) {
803             result += "Terminal";
804           } else {
805             bool arc_app_found = false;
806             for (const auto& arc_app : arc_test_.fake_apps()) {
807               if (app == ArcAppTest::GetAppId(arc_app)) {
808                 result += arc_app.name;
809                 arc_app_found = true;
810                 break;
811               }
812             }
813             if (!arc_app_found) {
814               result += app_service_test_.GetAppName(app);
815             }
816           }
817           break;
818         }
819         case ash::TYPE_BROWSER_SHORTCUT:
820           result += "Chrome";
821           break;
822         default:
823           result += "Unknown";
824           break;
825       }
826     }
827     return result;
828   }
829 
830   // Remember the order of unpinned but running applications for the current
831   // user.
RememberUnpinnedRunningApplicationOrder()832   void RememberUnpinnedRunningApplicationOrder() {
833     launcher_controller_->RememberUnpinnedRunningApplicationOrder();
834   }
835 
836   // Restore the order of running but unpinned applications for a given user.
RestoreUnpinnedRunningApplicationOrder(const AccountId & account_id)837   void RestoreUnpinnedRunningApplicationOrder(const AccountId& account_id) {
838     launcher_controller_->RestoreUnpinnedRunningApplicationOrder(
839         account_id.GetUserEmail());
840   }
841 
SendListOfArcApps()842   void SendListOfArcApps() {
843     arc_test_.app_instance()->SendRefreshAppList(arc_test_.fake_apps());
844   }
845 
SendListOfArcShortcuts()846   void SendListOfArcShortcuts() {
847     arc_test_.app_instance()->SendInstallShortcuts(arc_test_.fake_shortcuts());
848   }
849 
UninstallArcApps()850   void UninstallArcApps() {
851     arc_test_.app_instance()->SendRefreshAppList(
852         std::vector<arc::mojom::AppInfo>());
853   }
854 
855   // TODO(victorhsieh): Add test coverage for when ARC is started regardless
856   // Play Store opt-in status, and the followed opt-in and opt-out.
EnablePlayStore(bool enabled)857   void EnablePlayStore(bool enabled) {
858     arc::SetArcPlayStoreEnabledForProfile(profile(), enabled);
859     base::RunLoop().RunUntilIdle();
860   }
861 
ValidateArcState(bool arc_enabled,bool arc_managed,arc::ArcSessionManager::State state,const std::string & pin_status)862   void ValidateArcState(bool arc_enabled,
863                         bool arc_managed,
864                         arc::ArcSessionManager::State state,
865                         const std::string& pin_status) {
866     EXPECT_EQ(arc_enabled, arc::IsArcPlayStoreEnabledForProfile(profile()));
867     EXPECT_EQ(arc_managed,
868               arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile()));
869     EXPECT_EQ(state, arc_test_.arc_session_manager()->state());
870     EXPECT_EQ(pin_status, GetPinnedAppStatus());
871   }
872 
873   // Creates app window and set optional ARC application id.
CreateArcWindow(const std::string & window_app_id)874   views::Widget* CreateArcWindow(const std::string& window_app_id) {
875     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
876     params.bounds = gfx::Rect(5, 5, 20, 20);
877     params.context = GetContext();
878     views::Widget* widget = new views::Widget();
879     widget->Init(std::move(params));
880     // Set ARC id before showing the window to be recognized in
881     // ArcAppWindowLauncherController.
882     exo::SetShellApplicationId(widget->GetNativeWindow(), window_app_id);
883     widget->Show();
884     widget->Activate();
885     return widget;
886   }
887 
CreateAppInfo(const std::string & name,const std::string & activity,const std::string & package_name)888   arc::mojom::AppInfo CreateAppInfo(const std::string& name,
889                                     const std::string& activity,
890                                     const std::string& package_name) {
891     arc::mojom::AppInfo appinfo;
892     appinfo.name = name;
893     appinfo.package_name = package_name;
894     appinfo.activity = activity;
895     return appinfo;
896   }
897 
AddArcAppAndShortcut(const arc::mojom::AppInfo & app_info)898   std::string AddArcAppAndShortcut(const arc::mojom::AppInfo& app_info) {
899     ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
900     // Adding app to the prefs, and check that the app is accessible by id.
901     prefs->AddAppAndShortcut(
902         app_info.name, app_info.package_name, app_info.activity,
903         std::string() /* intent_uri */, std::string() /* icon_resource_id */,
904         false /* sticky */, true /* notifications_enabled */,
905         true /* app_ready */, false /* suspended */, false /* shortcut */,
906         true /* launchable */);
907     const std::string app_id =
908         ArcAppListPrefs::GetAppId(app_info.package_name, app_info.activity);
909     EXPECT_TRUE(prefs->GetApp(app_id));
910     app_service_test().FlushMojoCalls();
911     return app_id;
912   }
913 
NotifyOnTaskCreated(const arc::mojom::AppInfo & appinfo,int32_t task_id)914   void NotifyOnTaskCreated(const arc::mojom::AppInfo& appinfo,
915                            int32_t task_id) {
916     ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
917     prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity,
918                          appinfo.name, std::string());
919   }
920 
921   // Creates a window with TYPE_APP shelf item type and the given app_id.
CreateShelfAppWindow(const std::string & app_id)922   views::Widget* CreateShelfAppWindow(const std::string& app_id) {
923     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
924     params.context = GetContext();
925     params.bounds = gfx::Rect(5, 5, 20, 20);
926     views::Widget* widget = new views::Widget();
927     widget->Init(std::move(params));
928 
929     aura::Window* window = widget->GetNativeWindow();
930     const ash::ShelfID shelf_id(app_id);
931     window->SetProperty(ash::kShelfIDKey,
932                         new std::string(shelf_id.Serialize()));
933     window->SetProperty<int>(ash::kShelfItemTypeKey, ash::TYPE_APP);
934     window->SetProperty(ash::kAppIDKey, new std::string(app_id));
935 
936     widget->Show();
937     widget->Activate();
938     return widget;
939   }
940 
NotifyOnTaskDestroyed(int32_t task_id)941   void NotifyOnTaskDestroyed(int32_t task_id) {
942     ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
943     prefs->OnTaskDestroyed(task_id);
944   }
945 
946   // Add extension and allow AppService async callbacks to run.
AddExtension(const Extension * extension)947   void AddExtension(const Extension* extension) {
948     extension_service_->AddExtension(extension);
949     app_service_test_.WaitForAppService();
950   }
951 
952   // Remove extension and allow AppService async callbacks to run.
UnloadExtension(const std::string & extension_id,UnloadedExtensionReason reason)953   void UnloadExtension(const std::string& extension_id,
954                        UnloadedExtensionReason reason) {
955     extension_service_->UnloadExtension(extension_id, reason);
956     app_service_test_.WaitForAppService();
957   }
958 
app_service_test()959   apps::AppServiceTest& app_service_test() { return app_service_test_; }
960 
961   // Needed for extension service & friends to work.
962   scoped_refptr<Extension> extension_chrome_;
963   scoped_refptr<Extension> extension1_;
964   scoped_refptr<Extension> extension2_;
965   scoped_refptr<Extension> extension5_;
966   scoped_refptr<Extension> extension6_;
967   scoped_refptr<Extension> extension7_;
968   scoped_refptr<Extension> extension8_;
969   scoped_refptr<Extension> extension_gmail_app_;
970   scoped_refptr<Extension> extension_doc_app_;
971   scoped_refptr<Extension> extension_youtube_app_;
972   scoped_refptr<Extension> extension_files_app_;
973   scoped_refptr<Extension> extension_platform_app_;
974   scoped_refptr<Extension> arc_support_host_;
975 
976   ArcAppTest arc_test_;
977   bool auto_start_arc_test_ = false;
978   std::unique_ptr<ChromeLauncherController> launcher_controller_;
979   std::unique_ptr<ash::ShelfModel> model_;
980 
981   // |item_delegate_manager_| owns |test_controller_|.
982   ash::ShelfItemDelegate* test_controller_ = nullptr;
983 
984   extensions::ExtensionRegistry* extension_registry_ = nullptr;
985 
986   extensions::ExtensionService* extension_service_ = nullptr;
987 
988   app_list::AppListSyncableService* app_list_syncable_service_ = nullptr;
989 
990  private:
CreateTestBrowserWindowAura()991   TestBrowserWindow* CreateTestBrowserWindowAura() {
992     std::unique_ptr<aura::Window> window(
993         new aura::Window(nullptr, aura::client::WINDOW_TYPE_NORMAL));
994     window->set_id(0);
995     window->Init(ui::LAYER_TEXTURED);
996     aura::client::ParentWindowWithContext(window.get(), GetContext(),
997                                           gfx::Rect(200, 200));
998 
999     return new TestBrowserWindowAura(std::move(window));
1000   }
1001 
1002   apps::AppServiceTest app_service_test_;
1003 };
1004 
1005 class ChromeLauncherControllerWithArcTest
1006     : public ChromeLauncherControllerTest {
1007  protected:
ChromeLauncherControllerWithArcTest()1008   ChromeLauncherControllerWithArcTest() {
1009     auto_start_arc_test_ = true;
1010   }
1011 
1012   ChromeLauncherControllerWithArcTest(
1013       const ChromeLauncherControllerWithArcTest&) = delete;
1014   ChromeLauncherControllerWithArcTest& operator=(
1015       const ChromeLauncherControllerWithArcTest&) = delete;
1016   ~ChromeLauncherControllerWithArcTest() override = default;
1017 
SetUp()1018   void SetUp() override {
1019     // To prevent crash on test exit and pending decode request.
1020     ArcAppIcon::DisableSafeDecodingForTesting();
1021 
1022     ChromeLauncherControllerTest::SetUp();
1023   }
1024 };
1025 
1026 // Tests for feature SplitSettingsSync. Exists as a separate class because the
1027 // feature must be initialized before ChromeLauncherControllerTest::SetUp().
1028 class ChromeLauncherControllerSplitSettingsSyncTest
1029     : public ChromeLauncherControllerTest {
1030  public:
ChromeLauncherControllerSplitSettingsSyncTest()1031   ChromeLauncherControllerSplitSettingsSyncTest() {
1032     feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettingsSync);
1033   }
1034   ~ChromeLauncherControllerSplitSettingsSyncTest() override = default;
1035 
1036  private:
1037   base::test::ScopedFeatureList feature_list_;
1038 };
1039 
1040 // Tests for Lacros integration. Exists as a separate class because the feature
1041 // must be initialized before ChromeLauncherControllerTest::SetUp().
1042 class ChromeLauncherControllerLacrosTest : public ChromeLauncherControllerTest {
1043  public:
ChromeLauncherControllerLacrosTest()1044   ChromeLauncherControllerLacrosTest() {
1045     feature_list_.InitAndEnableFeature(chromeos::features::kLacrosSupport);
1046   }
1047   ChromeLauncherControllerLacrosTest(
1048       const ChromeLauncherControllerLacrosTest&) = delete;
1049   ChromeLauncherControllerLacrosTest& operator=(
1050       const ChromeLauncherControllerLacrosTest&) = delete;
1051   ~ChromeLauncherControllerLacrosTest() override = default;
1052 
1053  private:
1054   base::test::ScopedFeatureList feature_list_;
1055 };
1056 
1057 class ChromeLauncherControllerExtendedShelfTest
1058     : public ChromeLauncherControllerWithArcTest {
1059  protected:
1060   ChromeLauncherControllerExtendedShelfTest() = default;
1061   ChromeLauncherControllerExtendedShelfTest(
1062       const ChromeLauncherControllerExtendedShelfTest&) = delete;
1063   ChromeLauncherControllerExtendedShelfTest& operator=(
1064       const ChromeLauncherControllerExtendedShelfTest&) = delete;
1065   ~ChromeLauncherControllerExtendedShelfTest() override = default;
1066 
SetUp()1067   void SetUp() override {
1068     ChromeLauncherControllerWithArcTest::SetUp();
1069 
1070     StartPrefSyncService(syncer::SyncDataList());
1071 
1072     extension_service_->AddExtension(extension_gmail_app_.get());
1073     extension_service_->AddExtension(extension_doc_app_.get());
1074     extension_service_->AddExtension(extension_youtube_app_.get());
1075     extension_service_->AddExtension(extension_files_app_.get());
1076     extension_service_->AddExtension(arc_support_host_.get());
1077 
1078     std::string error;
1079     base::DictionaryValue manifest;
1080     manifest.SetString(extensions::manifest_keys::kVersion, "1");
1081     manifest.SetInteger(extensions::manifest_keys::kManifestVersion, 2);
1082     manifest.SetString(extensions::manifest_keys::kDescription,
1083                        "for testing pinned apps");
1084     // AppService checks the app's type. So set the
1085     // manifest_keys::kLaunchWebURL, so that the extension can get the type
1086     // from manifest value, and then AppService can get the extension's type.
1087     manifest.SetString(extensions::manifest_keys::kLaunchWebURL, kLaunchURL);
1088 
1089     const std::vector<std::pair<std::string, std::string>> extra_extensions = {
1090         {extension_misc::kCalendarAppId, "Calendar"},
1091         {extension_misc::kGoogleSheetsAppId, "Sheets"},
1092         {extension_misc::kGoogleSlidesAppId, "Slides"},
1093         {extension_misc::kCameraAppId, "Camera"},
1094         {extension_misc::kGooglePhotosAppId, "Photos"},
1095     };
1096 
1097     for (const auto& extension_id_name : extra_extensions) {
1098       manifest.SetString(extensions::manifest_keys::kName,
1099                          extension_id_name.second);
1100       scoped_refptr<Extension> extension = Extension::Create(
1101           base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
1102           extension_id_name.first, &error);
1103       extension_service_->AddExtension(extension.get());
1104       extra_extensions_.emplace_back(extension);
1105     }
1106   }
1107 
1108  private:
1109   std::vector<scoped_refptr<Extension>> extra_extensions_;
1110 };
1111 
1112 // A V1 windowed application.
1113 class V1App : public TestBrowserWindow {
1114  public:
V1App(Profile * profile,const std::string & app_name)1115   V1App(Profile* profile, const std::string& app_name) {
1116     Browser::CreateParams params = Browser::CreateParams::CreateForApp(
1117         kCrxAppPrefix + app_name, true /* trusted_source */, gfx::Rect(),
1118         profile, true);
1119     params.window = this;
1120     browser_ = std::unique_ptr<Browser>(Browser::Create(params));
1121     chrome::AddTabAt(browser_.get(), GURL(), 0, true);
1122   }
1123   V1App(const V1App&) = delete;
1124   V1App& operator=(const V1App&) = delete;
~V1App()1125   ~V1App() override {
1126     // close all tabs. Note that we do not need to destroy the browser itself.
1127     browser_->tab_strip_model()->CloseAllTabs();
1128   }
1129 
browser()1130   Browser* browser() { return browser_.get(); }
1131 
1132  private:
1133   // The associated browser with this app.
1134   std::unique_ptr<Browser> browser_;
1135 };
1136 
1137 // A V2 application window created with an |extension| and for a |profile|.
1138 // Upon destruction it will properly close the application.
1139 class V2App {
1140  public:
V2App(Profile * profile,const extensions::Extension * extension,extensions::AppWindow::WindowType window_type=extensions::AppWindow::WINDOW_TYPE_DEFAULT)1141   V2App(Profile* profile,
1142         const extensions::Extension* extension,
1143         extensions::AppWindow::WindowType window_type =
1144             extensions::AppWindow::WINDOW_TYPE_DEFAULT)
1145       : creator_web_contents_(
1146             content::WebContentsTester::CreateTestWebContents(profile,
1147                                                               nullptr)) {
1148     window_ = new extensions::AppWindow(profile, new ChromeAppDelegate(true),
1149                                         extension);
1150     extensions::AppWindow::CreateParams params;
1151     params.window_type = window_type;
1152     // Note: normally, the creator RFH is the background page of the
1153     // app/extension
1154     // calling chrome.app.window.create. For unit testing purposes, just passing
1155     // in a random RenderFrameHost is Good Enough™.
1156     window_->Init(GURL(std::string()),
1157                   new extensions::AppWindowContentsImpl(window_),
1158                   creator_web_contents_->GetMainFrame(), params);
1159   }
1160 
1161   V2App(const V2App&) = delete;
1162   V2App& operator=(const V2App&) = delete;
~V2App()1163   virtual ~V2App() {
1164     content::WebContentsDestroyedWatcher destroyed_watcher(
1165         window_->web_contents());
1166     window_->GetBaseWindow()->Close();
1167     destroyed_watcher.Wait();
1168   }
1169 
window()1170   extensions::AppWindow* window() { return window_; }
1171 
1172  private:
1173   std::unique_ptr<content::WebContents> creator_web_contents_;
1174 
1175   // The app window which represents the application. Note that the window
1176   // deletes itself asynchronously after window_->GetBaseWindow()->Close() gets
1177   // called.
1178   extensions::AppWindow* window_;
1179 };
1180 
1181 // The testing framework to test multi profile scenarios.
1182 class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest
1183     : public ChromeLauncherControllerTest {
1184  protected:
1185   MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() = default;
1186   MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest(
1187       const MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest&) =
1188       delete;
1189   MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest& operator=(
1190       const MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest&) =
1191       delete;
1192   ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() override =
1193       default;
1194 
1195   // Overwrite the Setup function to enable multi profile and needed objects.
SetUp()1196   void SetUp() override {
1197     // Initialize the UserManager singleton to a fresh FakeUserManager instance.
1198     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
1199         std::make_unique<chromeos::FakeChromeUserManager>());
1200 
1201     // Initialize the rest.
1202     ChromeLauncherControllerTest::SetUp();
1203 
1204     // Initialize WallpaperControllerClient.
1205     wallpaper_controller_client_ =
1206         std::make_unique<WallpaperControllerClient>();
1207     wallpaper_controller_client_->InitForTesting(&test_wallpaper_controller_);
1208 
1209     // Ensure there are multiple profiles. User 0 is created during setup.
1210     CreateMultiUserProfile("user1");
1211     ASSERT_TRUE(SessionControllerClientImpl::IsMultiProfileAvailable());
1212   }
1213 
TearDown()1214   void TearDown() override {
1215     ChromeLauncherControllerTest::TearDown();
1216     user_manager_enabler_.reset();
1217     wallpaper_controller_client_.reset();
1218 
1219     // A Task is leaked if we don't destroy everything, then run the message
1220     // loop.
1221     base::RunLoop().RunUntilIdle();
1222   }
1223 
MaybeStartWebAppProvider()1224   void MaybeStartWebAppProvider() override {
1225     // Deliberately do nothing; the provider is started in
1226     // CreateMultiUserProfile()
1227   }
1228 
1229   // Creates a profile for a given |user_name|. Note that this class will keep
1230   // the ownership of the created object.
CreateMultiUserProfile(const std::string & user_name)1231   TestingProfile* CreateMultiUserProfile(const std::string& user_name) {
1232     const std::string email_string = user_name + "@example.com";
1233     const AccountId account_id(AccountId::FromUserEmail(email_string));
1234     // Add a user to the fake user manager.
1235     auto* user = GetFakeUserManager()->AddUser(account_id);
1236     ash_test_helper()->test_session_controller_client()->AddUserSession(
1237         user->GetDisplayEmail());
1238 
1239     GetFakeUserManager()->LoginUser(account_id);
1240 
1241     TestingProfile* profile =
1242         profile_manager()->CreateTestingProfile(account_id.GetUserEmail());
1243     EXPECT_TRUE(profile);
1244 
1245     web_app::TestWebAppProvider::Get(profile)->Start();
1246 
1247     // Remember the profile name so that we can destroy it upon destruction.
1248     created_profiles_[profile] = account_id.GetUserEmail();
1249     if (MultiUserWindowManagerHelper::GetInstance())
1250       MultiUserWindowManagerHelper::GetInstance()->AddUser(profile);
1251     if (launcher_controller_)
1252       launcher_controller_->AdditionalUserAddedToSession(profile);
1253     return profile;
1254   }
1255 
1256   // Switch to another user.
SwitchActiveUser(const AccountId & account_id)1257   void SwitchActiveUser(const AccountId& account_id) {
1258     GetFakeUserManager()->SwitchActiveUser(account_id);
1259     ash::MultiUserWindowManagerImpl::Get()->SetAnimationSpeedForTest(
1260         ash::MultiUserWindowManagerImpl::ANIMATION_SPEED_DISABLED);
1261     ash::MultiUserWindowManagerImpl::Get()->OnActiveUserSessionChanged(
1262         account_id);
1263   }
1264 
1265   // Creates a browser with a |profile| and load a tab with a |title| and |url|.
CreateBrowserAndTabWithProfile(Profile * profile,const std::string & title,const std::string & url)1266   std::unique_ptr<Browser> CreateBrowserAndTabWithProfile(
1267       Profile* profile,
1268       const std::string& title,
1269       const std::string& url) {
1270     std::unique_ptr<Browser> browser(
1271         CreateBrowserWithTestWindowForProfile(profile));
1272     chrome::NewTab(browser.get());
1273 
1274     browser->window()->Show();
1275     NavigateAndCommitActiveTabWithTitle(browser.get(), GURL(url),
1276                                         ASCIIToUTF16(title));
1277     return browser;
1278   }
1279 
1280   // Creates a running V1 application.
1281   // Note that with the use of the launcher_controller_helper as done below,
1282   // this is only usable with a single v1 application.
CreateRunningV1App(Profile * profile,const std::string & app_name,const std::string & url)1283   V1App* CreateRunningV1App(Profile* profile,
1284                             const std::string& app_name,
1285                             const std::string& url) {
1286     V1App* v1_app = new V1App(profile, app_name);
1287     NavigateAndCommitActiveTabWithTitle(v1_app->browser(), GURL(url),
1288                                         base::string16());
1289     return v1_app;
1290   }
1291 
1292   // Override BrowserWithTestWindowTest:
CreateProfile()1293   TestingProfile* CreateProfile() override {
1294     return CreateMultiUserProfile("user0");
1295   }
1296 
1297  private:
1298   typedef std::map<Profile*, std::string> ProfileToNameMap;
1299 
GetFakeUserManager()1300   chromeos::FakeChromeUserManager* GetFakeUserManager() {
1301     return static_cast<chromeos::FakeChromeUserManager*>(
1302         user_manager::UserManager::Get());
1303   }
1304 
1305   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
1306 
1307   std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
1308 
1309   TestWallpaperController test_wallpaper_controller_;
1310 
1311   ProfileToNameMap created_profiles_;
1312 };
1313 
1314 class ChromeLauncherControllerMultiProfileWithArcTest
1315     : public MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest {
1316  protected:
ChromeLauncherControllerMultiProfileWithArcTest()1317   ChromeLauncherControllerMultiProfileWithArcTest() {
1318     auto_start_arc_test_ = true;
1319   }
1320   ChromeLauncherControllerMultiProfileWithArcTest(
1321       const ChromeLauncherControllerMultiProfileWithArcTest&) = delete;
1322   ChromeLauncherControllerMultiProfileWithArcTest& operator=(
1323       const ChromeLauncherControllerMultiProfileWithArcTest&) = delete;
1324   ~ChromeLauncherControllerMultiProfileWithArcTest() override = default;
1325 };
1326 
TEST_F(ChromeLauncherControllerTest,DefaultApps)1327 TEST_F(ChromeLauncherControllerTest, DefaultApps) {
1328   InitLauncherController();
1329 
1330   // The model should only contain the browser shortcut item.
1331   EXPECT_EQ("Chrome", GetPinnedAppStatus());
1332 
1333   // Pinning the non-default app. It should appear at the end. No default app
1334   // is currently installed.
1335   extension_service_->AddExtension(extension1_.get());
1336   launcher_controller_->PinAppWithID(extension1_->id());
1337   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
1338 
1339   // Install default apps in reverse order, compared how they are declared.
1340   // However pin positions should be in the order as they declared. Note,
1341   // default apps appear on shelf between manually pinned App1.
1342 
1343   // Prefs are not yet synced. No default pin appears.
1344   AddExtension(extension_youtube_app_.get());
1345   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
1346 
1347   StartPrefSyncService(syncer::SyncDataList());
1348   EXPECT_EQ("Chrome, Youtube, App1", GetPinnedAppStatus());
1349 
1350   AddExtension(extension_doc_app_.get());
1351   EXPECT_EQ("Chrome, Doc, Youtube, App1", GetPinnedAppStatus());
1352   AddExtension(extension_gmail_app_.get());
1353   EXPECT_EQ("Chrome, Gmail, Doc, Youtube, App1", GetPinnedAppStatus());
1354   AddExtension(extension_files_app_.get());
1355   EXPECT_EQ("Chrome, Files, Gmail, Doc, Youtube, App1", GetPinnedAppStatus());
1356 }
1357 
TEST_F(ChromeLauncherControllerSplitSettingsSyncTest,DefaultApps)1358 TEST_F(ChromeLauncherControllerSplitSettingsSyncTest, DefaultApps) {
1359   // Simulate a user who opted out of sync.
1360   syncer::SyncService* sync_service =
1361       ProfileSyncServiceFactory::GetForProfile(profile());
1362   sync_service->GetUserSettings()->SetOsSyncFeatureEnabled(false);
1363 
1364   InitLauncherController();
1365   EXPECT_EQ("Chrome", GetPinnedAppStatus());
1366 
1367   // Simulate the default app loader installing some apps. Don't start the
1368   // pref sync service, because this user opted out of sync.
1369   AddExtension(extension_youtube_app_.get());
1370   AddExtension(extension_doc_app_.get());
1371   AddExtension(extension_gmail_app_.get());
1372 
1373   // Default apps are pinned.
1374   EXPECT_EQ("Chrome, Gmail, Doc, Youtube", GetPinnedAppStatus());
1375 }
1376 
TEST_F(ChromeLauncherControllerLacrosTest,LacrosPinnedByDefault)1377 TEST_F(ChromeLauncherControllerLacrosTest, LacrosPinnedByDefault) {
1378   // Checking to see if Lacros is allowed requires a user.
1379   auto user_manager = std::make_unique<chromeos::FakeChromeUserManager>();
1380   auto* fake_user_manager = user_manager.get();
1381   user_manager::ScopedUserManager scoped_user_manager(std::move(user_manager));
1382   AccountId account_id = AccountId::FromUserEmail("user@example.com");
1383   user_manager::User* user = fake_user_manager->AddUser(account_id);
1384   fake_user_manager->LoginUser(account_id);
1385 
1386   TestingProfile::Builder profile_builder;
1387   profile_builder.SetProfileName(account_id.GetUserEmail());
1388   std::unique_ptr<TestingProfile> testing_profile = profile_builder.Build();
1389   chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
1390       user, testing_profile.get());
1391 
1392   InitLauncherController();
1393   EXPECT_EQ("Chrome, Lacros", GetPinnedAppStatus());
1394 }
1395 
TEST_F(ChromeLauncherControllerExtendedShelfTest,ExtendedShelfDefault)1396 TEST_F(ChromeLauncherControllerExtendedShelfTest, ExtendedShelfDefault) {
1397   base::test::ScopedFeatureList scoped_feature_list;
1398   scoped_feature_list.InitAndEnableFeatureWithParameters(
1399       kEnableExtendedShelfLayout,
1400       {std::pair<std::string, std::string>("app_count", "0")});
1401 
1402   InitLauncherController();
1403   EXPECT_EQ("Chrome, Files, Gmail, Doc, Youtube, Play Store",
1404             GetPinnedAppStatus());
1405 }
1406 
TEST_F(ChromeLauncherControllerExtendedShelfTest,ExtendedShelf7Apps)1407 TEST_F(ChromeLauncherControllerExtendedShelfTest, ExtendedShelf7Apps) {
1408   base::test::ScopedFeatureList scoped_feature_list;
1409   scoped_feature_list.InitAndEnableFeatureWithParameters(
1410       kEnableExtendedShelfLayout,
1411       {std::pair<std::string, std::string>("app_count", "7")});
1412 
1413   InitLauncherController();
1414   EXPECT_EQ("Chrome, Files, Gmail, Doc, Photos, Youtube, Play Store",
1415             GetPinnedAppStatus());
1416 }
1417 
TEST_F(ChromeLauncherControllerExtendedShelfTest,ExtendedShelf10Apps)1418 TEST_F(ChromeLauncherControllerExtendedShelfTest, ExtendedShelf10Apps) {
1419   base::test::ScopedFeatureList scoped_feature_list;
1420   scoped_feature_list.InitAndEnableFeatureWithParameters(
1421       kEnableExtendedShelfLayout,
1422       {std::pair<std::string, std::string>("app_count", "10")});
1423 
1424   InitLauncherController();
1425   EXPECT_EQ(
1426       "Chrome, Files, Gmail, Calendar, Doc, Sheets, Slides, Camera, Photos, "
1427       "Play Store",
1428       GetPinnedAppStatus());
1429 }
1430 
TEST_F(ChromeLauncherControllerExtendedShelfTest,UpgradeFromDefault)1431 TEST_F(ChromeLauncherControllerExtendedShelfTest, UpgradeFromDefault) {
1432   InitLauncherController();
1433   EXPECT_EQ("Chrome, Files, Gmail, Doc, Youtube, Play Store",
1434             GetPinnedAppStatus());
1435 
1436   // Upgrade happens only in case default layout is active.
1437   base::test::ScopedFeatureList scoped_feature_list;
1438   scoped_feature_list.InitAndEnableFeatureWithParameters(
1439       kEnableExtendedShelfLayout,
1440       {std::pair<std::string, std::string>("app_count", "10")});
1441 
1442   // Trigger layout update, app_id does not matter.
1443   AddExtension(extension1_.get());
1444 
1445   EXPECT_EQ(
1446       "Chrome, Files, Gmail, Calendar, Doc, Sheets, Slides, Camera, Photos, "
1447       "Play Store",
1448       GetPinnedAppStatus());
1449 }
1450 
TEST_F(ChromeLauncherControllerExtendedShelfTest,NoDefaultAfterExperimental)1451 TEST_F(ChromeLauncherControllerExtendedShelfTest, NoDefaultAfterExperimental) {
1452   const std::string expectations =
1453       "Chrome, Files, Gmail, Calendar, Doc, Sheets, "
1454       "Slides, Camera, Photos, Play Store";
1455   {
1456     base::test::ScopedFeatureList scoped_feature_list;
1457     scoped_feature_list.InitAndEnableFeatureWithParameters(
1458         kEnableExtendedShelfLayout,
1459         {std::pair<std::string, std::string>("app_count", "10")});
1460 
1461     InitLauncherController();
1462     EXPECT_EQ(expectations, GetPinnedAppStatus());
1463 
1464     // Trigger layout update, app_id does not matter. Experiment is still
1465     // forced.
1466     AddExtension(extension1_.get());
1467 
1468     // Youtube is included into default but not to expermenetal. Refreshing
1469     // should not affect layout.
1470     EXPECT_EQ(expectations, GetPinnedAppStatus());
1471   }
1472 
1473   // Re-update but experiment is off now. No change to layout.
1474   AddExtension(extension2_.get());
1475   EXPECT_EQ(expectations, GetPinnedAppStatus());
1476 }
1477 
TEST_F(ChromeLauncherControllerExtendedShelfTest,NoUpgradeFromNonDefault)1478 TEST_F(ChromeLauncherControllerExtendedShelfTest, NoUpgradeFromNonDefault) {
1479   InitLauncherController();
1480   launcher_controller_->UnpinAppWithID(extension_misc::kYoutubeAppId);
1481   EXPECT_EQ("Chrome, Files, Gmail, Doc, Play Store", GetPinnedAppStatus());
1482 
1483   // Upgrade does not happen due to default pin layout change.
1484   base::test::ScopedFeatureList scoped_feature_list;
1485   scoped_feature_list.InitAndEnableFeatureWithParameters(
1486       kEnableExtendedShelfLayout,
1487       {std::pair<std::string, std::string>("app_count", "10")});
1488 
1489   // Trigger layout update, app_id does not matter.
1490   AddExtension(extension1_.get());
1491 
1492   EXPECT_EQ("Chrome, Files, Gmail, Doc, Play Store", GetPinnedAppStatus());
1493 }
1494 
TEST_F(ChromeLauncherControllerWithArcTest,ArcAppPinCrossPlatformWorkflow)1495 TEST_F(ChromeLauncherControllerWithArcTest, ArcAppPinCrossPlatformWorkflow) {
1496   // Work on ARC disabled platform first.
1497   const std::string arc_app_id1 =
1498       ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
1499   const std::string arc_app_id2 =
1500       ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
1501   const std::string arc_app_id3 =
1502       ArcAppTest::GetAppId(arc_test_.fake_apps()[2]);
1503 
1504   InitLauncherController();
1505 
1506   extension_service_->AddExtension(extension1_.get());
1507   extension_service_->AddExtension(extension2_.get());
1508   extension_service_->AddExtension(extension_gmail_app_.get());
1509   app_service_test().WaitForAppService();
1510 
1511   // extension 1, 3 are pinned by user
1512   syncer::SyncChangeList sync_list;
1513   InsertAddPinChange(&sync_list, 0, extension1_->id());
1514   InsertAddPinChange(&sync_list, 1, arc_app_id1);
1515   InsertAddPinChange(&sync_list, 2, extension2_->id());
1516   InsertAddPinChange(&sync_list, 3, arc_app_id2);
1517   InsertAddPinChange(&sync_list, 4, extension_gmail_app_->id());
1518   SendPinChanges(sync_list, true);
1519   SetShelfChromeIconIndex(1);
1520 
1521   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1522   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
1523   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1524   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
1525   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1526   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1527   EXPECT_EQ("App1, Chrome, App2, Gmail", GetPinnedAppStatus());
1528 
1529   // Persist pin state, we don't have active pin for ARC apps yet, but pin
1530   // model should have it.
1531   syncer::SyncDataList copy_sync_list =
1532       app_list_syncable_service_->GetAllSyncDataForTesting();
1533 
1534   ResetLauncherController();
1535   SendPinChanges(syncer::SyncChangeList(), true);
1536   StopAppSyncService();
1537   EXPECT_EQ(0U, app_list_syncable_service_->sync_items().size());
1538 
1539   // Move to ARC enabled platform, restart syncing with stored data.
1540   StartAppSyncService(copy_sync_list);
1541   RecreateLauncherController()->Init();
1542 
1543   // Pins must be automatically updated.
1544   SendListOfArcApps();
1545   app_service_test().WaitForAppService();
1546   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1547   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
1548   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1549   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
1550   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1551   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1552 
1553   EXPECT_EQ("App1, Chrome, Fake App 0, App2, Fake App 1, Gmail",
1554             GetPinnedAppStatus());
1555 
1556   // Now move pins on ARC enabled platform.
1557   model_->Move(0, 3);
1558   model_->Move(2, 0);
1559   model_->Move(2, 4);
1560   model_->Move(3, 1);
1561   EXPECT_EQ("App2, Fake App 1, Chrome, App1, Fake App 0, Gmail",
1562             GetPinnedAppStatus());
1563 
1564   app_service_test().WaitForAppService();
1565   copy_sync_list = app_list_syncable_service_->GetAllSyncDataForTesting();
1566 
1567   ResetLauncherController();
1568   ResetPinModel();
1569 
1570   SendPinChanges(syncer::SyncChangeList(), true);
1571   StopAppSyncService();
1572   EXPECT_EQ(0U, app_list_syncable_service_->sync_items().size());
1573 
1574   // Move back to ARC disabled platform.
1575   EnablePlayStore(false);
1576   StartAppSyncService(copy_sync_list);
1577   RecreateLauncherController()->Init();
1578 
1579   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1580   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
1581   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1582   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
1583   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1584   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1585   EXPECT_EQ("App2, Chrome, App1, Gmail", GetPinnedAppStatus());
1586 
1587   // Now move/remove pins on ARC disabled platform.
1588   model_->Move(3, 1);
1589   launcher_controller_->UnpinAppWithID(extension2_->id());
1590   EXPECT_EQ("Gmail, Chrome, App1", GetPinnedAppStatus());
1591   EnablePlayStore(true);
1592 
1593   SendListOfArcApps();
1594   app_service_test().WaitForAppService();
1595 
1596   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1597   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
1598   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1599   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
1600   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1601   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1602   EXPECT_EQ("Fake App 1, Gmail, Chrome, App1, Fake App 0",
1603             GetPinnedAppStatus());
1604 }
1605 
1606 // Ensure correct merging of policy pinned apps and user pinned apps.
TEST_F(ChromeLauncherControllerTest,MergePolicyAndUserPrefPinnedApps)1607 TEST_F(ChromeLauncherControllerTest, MergePolicyAndUserPrefPinnedApps) {
1608   InitLauncherController();
1609 
1610   extension_service_->AddExtension(extension1_.get());
1611   extension_service_->AddExtension(extension_gmail_app_.get());
1612   extension_service_->AddExtension(extension_doc_app_.get());
1613   extension_service_->AddExtension(extension5_.get());
1614   // extension 1, 3 are pinned by user
1615   syncer::SyncChangeList sync_list;
1616   InsertAddPinChange(&sync_list, 0, extension1_->id());
1617   InsertAddPinChange(&sync_list, 1, extension_misc::kChromeAppId);
1618   InsertAddPinChange(&sync_list, 2, extension_gmail_app_->id());
1619   SendPinChanges(sync_list, true);
1620 
1621   base::ListValue policy_value;
1622   // extension 2 4 are pinned by policy
1623   AppendPrefValue(&policy_value, extension2_->id());
1624   AppendPrefValue(&policy_value, extension_doc_app_->id());
1625   profile()->GetTestingPrefService()->SetManagedPref(
1626       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
1627 
1628   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1629   // 2 is not pinned as it's not installed
1630   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1631   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1632   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_doc_app_->id()));
1633   // install extension 2 and check
1634   AddExtension(extension2_.get());
1635   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1636 
1637   // Check user can manually pin or unpin these apps
1638   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
1639             GetPinnableForAppID(extension1_->id(), profile()));
1640   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
1641             GetPinnableForAppID(extension2_->id(), profile()));
1642   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
1643             GetPinnableForAppID(extension_gmail_app_->id(), profile()));
1644   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
1645             GetPinnableForAppID(extension_doc_app_->id(), profile()));
1646 
1647   // Check the order of shelf pinned apps
1648   EXPECT_EQ("App2, Doc, App1, Chrome, Gmail", GetPinnedAppStatus());
1649 }
1650 
1651 // Check that the restauration of launcher items is happening in the same order
1652 // as the user has pinned them (on another system) when they are synced reverse
1653 // order.
TEST_F(ChromeLauncherControllerTest,RestoreDefaultAppsReverseOrder)1654 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsReverseOrder) {
1655   InitLauncherController();
1656 
1657   syncer::SyncChangeList sync_list;
1658   InsertAddPinChange(&sync_list, 0, extension1_->id());
1659   InsertAddPinChange(&sync_list, 1, extension2_->id());
1660   InsertAddPinChange(&sync_list, 2, extension_gmail_app_->id());
1661   SendPinChanges(sync_list, true);
1662 
1663   // The model should only contain the browser shortcut and app list items.
1664   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1665   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1666   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1667   EXPECT_EQ("Chrome", GetPinnedAppStatus());
1668 
1669   // Installing |extension_gmail_app_| should add it to the shelf - behind the
1670   // chrome icon.
1671   ash::ShelfItem item;
1672   AddExtension(extension_gmail_app_.get());
1673   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1674   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1675   EXPECT_EQ("Chrome, Gmail", GetPinnedAppStatus());
1676 
1677   // Installing |extension2_| should add it to the launcher - behind the
1678   // chrome icon, but in first location.
1679   AddExtension(extension2_.get());
1680   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1681   EXPECT_EQ("Chrome, App2, Gmail", GetPinnedAppStatus());
1682 
1683   // Installing |extension1_| should add it to the launcher - behind the
1684   // chrome icon, but in first location.
1685   AddExtension(extension1_.get());
1686   EXPECT_EQ("Chrome, App1, App2, Gmail", GetPinnedAppStatus());
1687 }
1688 
1689 // Check that the restauration of launcher items is happening in the same order
1690 // as the user has pinned them (on another system) when they are synced random
1691 // order.
TEST_F(ChromeLauncherControllerTest,RestoreDefaultAppsRandomOrder)1692 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrder) {
1693   InitLauncherController();
1694 
1695   syncer::SyncChangeList sync_list;
1696   InsertAddPinChange(&sync_list, 0, extension1_->id());
1697   InsertAddPinChange(&sync_list, 1, extension2_->id());
1698   InsertAddPinChange(&sync_list, 2, extension_gmail_app_->id());
1699   SendPinChanges(sync_list, true);
1700 
1701   // The model should only contain the browser shortcut and app list items.
1702   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1703   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1704   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1705   EXPECT_EQ("Chrome", GetPinnedAppStatus());
1706 
1707   // Installing |extension2_| should add it to the launcher - behind the
1708   // chrome icon.
1709   AddExtension(extension2_.get());
1710   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1711   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1712   EXPECT_EQ("Chrome, App2", GetPinnedAppStatus());
1713 
1714   // Installing |extension1_| should add it to the launcher - behind the
1715   // chrome icon, but in first location.
1716   AddExtension(extension1_.get());
1717   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1718   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
1719 
1720   // Installing |extension_gmail_app_| should add it to the launcher - behind
1721   // the chrome icon, but in first location.
1722   AddExtension(extension_gmail_app_.get());
1723   EXPECT_EQ("Chrome, App1, App2, Gmail", GetPinnedAppStatus());
1724 }
1725 
1726 // Check that the restauration of launcher items is happening in the same order
1727 // as the user has pinned / moved them (on another system) when they are synced
1728 // random order - including the chrome icon.
TEST_F(ChromeLauncherControllerTest,RestoreDefaultAppsRandomOrderChromeMoved)1729 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrderChromeMoved) {
1730   InitLauncherController();
1731 
1732   syncer::SyncChangeList sync_list;
1733   InsertAddPinChange(&sync_list, 0, extension1_->id());
1734   InsertAddPinChange(&sync_list, 1, extension_misc::kChromeAppId);
1735   InsertAddPinChange(&sync_list, 2, extension2_->id());
1736   InsertAddPinChange(&sync_list, 3, extension_gmail_app_->id());
1737   SendPinChanges(sync_list, true);
1738 
1739   // The model should only contain the browser shortcut and app list items.
1740   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1741   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1742   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1743   EXPECT_EQ("Chrome", GetPinnedAppStatus());
1744 
1745   // Installing |extension2_| should add it to the shelf - behind the
1746   // chrome icon.
1747   ash::ShelfItem item;
1748   AddExtension(extension2_.get());
1749   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1750   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1751   EXPECT_EQ("Chrome, App2", GetPinnedAppStatus());
1752 
1753   // Installing |extension1_| should add it to the launcher - behind the
1754   // chrome icon, but in first location.
1755   AddExtension(extension1_.get());
1756   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
1757   EXPECT_EQ("App1, Chrome, App2", GetPinnedAppStatus());
1758 
1759   // Installing |extension_gmail_app_| should add it to the launcher - behind
1760   // the chrome icon, but in first location.
1761   AddExtension(extension_gmail_app_.get());
1762   EXPECT_EQ("App1, Chrome, App2, Gmail", GetPinnedAppStatus());
1763 }
1764 
1765 // Check that syncing to a different state does the correct thing.
TEST_F(ChromeLauncherControllerTest,RestoreDefaultAppsResyncOrder)1766 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsResyncOrder) {
1767   InitLauncherController();
1768 
1769   syncer::SyncChangeList sync_list0;
1770   InsertAddPinChange(&sync_list0, 0, extension1_->id());
1771   InsertAddPinChange(&sync_list0, 1, extension2_->id());
1772   InsertAddPinChange(&sync_list0, 2, extension_gmail_app_->id());
1773   SendPinChanges(sync_list0, true);
1774 
1775   // The shelf layout has always one static item at the beginning (App List).
1776   AddExtension(extension2_.get());
1777   EXPECT_EQ("Chrome, App2", GetPinnedAppStatus());
1778   AddExtension(extension1_.get());
1779   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
1780   AddExtension(extension_gmail_app_.get());
1781   EXPECT_EQ("Chrome, App1, App2, Gmail", GetPinnedAppStatus());
1782 
1783   // Change the order with increasing chrome position and decreasing position.
1784   syncer::SyncChangeList sync_list1;
1785   InsertAddPinChange(&sync_list1, 0, extension_gmail_app_->id());
1786   InsertAddPinChange(&sync_list1, 1, extension1_->id());
1787   InsertAddPinChange(&sync_list1, 2, extension2_->id());
1788   InsertAddPinChange(&sync_list1, 3, extension_misc::kChromeAppId);
1789   SendPinChanges(sync_list1, true);
1790   EXPECT_EQ("Gmail, App1, App2, Chrome", GetPinnedAppStatus());
1791 
1792   syncer::SyncChangeList sync_list2;
1793   InsertAddPinChange(&sync_list2, 0, extension2_->id());
1794   InsertAddPinChange(&sync_list2, 1, extension_gmail_app_->id());
1795   InsertAddPinChange(&sync_list2, 2, extension_misc::kChromeAppId);
1796   InsertAddPinChange(&sync_list2, 3, extension1_->id());
1797   SendPinChanges(sync_list2, true);
1798   EXPECT_EQ("App2, Gmail, Chrome, App1", GetPinnedAppStatus());
1799 
1800   // Check that the chrome icon can also be at the first possible location.
1801   syncer::SyncChangeList sync_list3;
1802   InsertAddPinChange(&sync_list3, 0, extension_gmail_app_->id());
1803   InsertAddPinChange(&sync_list3, 1, extension2_->id());
1804   InsertAddPinChange(&sync_list3, 2, extension1_->id());
1805   SendPinChanges(sync_list3, true);
1806   EXPECT_EQ("Chrome, Gmail, App2, App1", GetPinnedAppStatus());
1807 
1808   // Check that unloading of extensions works as expected.
1809   UnloadExtension(extension1_->id(), UnloadedExtensionReason::UNINSTALL);
1810   EXPECT_EQ("Chrome, Gmail, App2", GetPinnedAppStatus());
1811 
1812   UnloadExtension(extension2_->id(), UnloadedExtensionReason::UNINSTALL);
1813   EXPECT_EQ("Chrome, Gmail", GetPinnedAppStatus());
1814 
1815   // Check that an update of an extension does not crash the system.
1816   UnloadExtension(extension_gmail_app_->id(), UnloadedExtensionReason::UPDATE);
1817   EXPECT_EQ("Chrome, Gmail", GetPinnedAppStatus());
1818 }
1819 
1820 // Test the V1 app interaction flow: run it, activate it, close it.
TEST_F(ChromeLauncherControllerTest,V1AppRunActivateClose)1821 TEST_F(ChromeLauncherControllerTest, V1AppRunActivateClose) {
1822   InitLauncherController();
1823   // The model should only contain the browser shortcut item.
1824   EXPECT_EQ(1, model_->item_count());
1825   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1826   EXPECT_EQ(nullptr,
1827             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1828 
1829   // Reporting that the app is running should create a new shelf item.
1830   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1831   EXPECT_EQ(2, model_->item_count());
1832   EXPECT_EQ(ash::TYPE_APP, model_->items()[1].type);
1833   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1834   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1835   EXPECT_NE(nullptr,
1836             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1837 
1838   // Reporting that the app is running again should have no effect.
1839   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1840   EXPECT_EQ(2, model_->item_count());
1841   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1842 
1843   // Reporting that the app is closed should remove its shelf item.
1844   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1845   EXPECT_EQ(1, model_->item_count());
1846   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1847   EXPECT_EQ(nullptr,
1848             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1849 
1850   // Reporting that the app is closed again should have no effect.
1851   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1852   EXPECT_EQ(1, model_->item_count());
1853 }
1854 
1855 // Test the V1 app interaction flow: pin it, run it, close it, unpin it.
TEST_F(ChromeLauncherControllerTest,V1AppPinRunCloseUnpin)1856 TEST_F(ChromeLauncherControllerTest, V1AppPinRunCloseUnpin) {
1857   InitLauncherController();
1858   // The model should only contain the browser shortcut.
1859   EXPECT_EQ(1, model_->item_count());
1860   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1861   EXPECT_EQ(nullptr,
1862             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1863 
1864   // Pinning the app should create a new shelf item.
1865   launcher_controller_->PinAppWithID(extension1_->id());
1866   EXPECT_EQ(2, model_->item_count());
1867   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1868   EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[1].status);
1869   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1870   EXPECT_NE(nullptr,
1871             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1872 
1873   // Reporting that the app is running should just update the existing item.
1874   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1875   EXPECT_EQ(2, model_->item_count());
1876   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1877   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1878   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1879   EXPECT_NE(nullptr,
1880             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1881 
1882   // Reporting that the app is closed should just update the existing item.
1883   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1884   EXPECT_EQ(2, model_->item_count());
1885   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1886   EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[1].status);
1887   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1888   EXPECT_NE(nullptr,
1889             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1890 
1891   // Unpinning the app should remove its shelf item.
1892   launcher_controller_->UnpinAppWithID(extension1_->id());
1893   EXPECT_EQ(1, model_->item_count());
1894   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1895   EXPECT_EQ(nullptr,
1896             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1897 }
1898 
1899 // Test the V1 app interaction flow: run it, pin it, close it, unpin it.
TEST_F(ChromeLauncherControllerTest,V1AppRunPinCloseUnpin)1900 TEST_F(ChromeLauncherControllerTest, V1AppRunPinCloseUnpin) {
1901   InitLauncherController();
1902 
1903   // The model should only contain the browser shortcut.
1904   EXPECT_EQ(1, model_->item_count());
1905   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1906   EXPECT_EQ(nullptr,
1907             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1908 
1909   // Reporting that the app is running should create a new shelf item.
1910   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1911   EXPECT_EQ(2, model_->item_count());
1912   EXPECT_EQ(ash::TYPE_APP, model_->items()[1].type);
1913   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1914   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1915   EXPECT_NE(nullptr,
1916             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1917 
1918   // Pinning the app should just update the existing item.
1919   launcher_controller_->PinAppWithID(extension1_->id());
1920   EXPECT_EQ(2, model_->item_count());
1921   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1922   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1923   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1924   EXPECT_NE(nullptr,
1925             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1926 
1927   // Reporting that the app is closed should just update the existing item.
1928   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1929   EXPECT_EQ(2, model_->item_count());
1930   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1931   EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[1].status);
1932   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1933   EXPECT_NE(nullptr,
1934             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1935 
1936   // Unpinning the app should remove its shelf item.
1937   launcher_controller_->UnpinAppWithID(extension1_->id());
1938   EXPECT_EQ(1, model_->item_count());
1939   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1940   EXPECT_EQ(nullptr,
1941             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1942 }
1943 
1944 // Test the V1 app interaction flow: pin it, run it, unpin it, close it.
TEST_F(ChromeLauncherControllerTest,V1AppPinRunUnpinClose)1945 TEST_F(ChromeLauncherControllerTest, V1AppPinRunUnpinClose) {
1946   InitLauncherController();
1947 
1948   // The model should only contain the browser shortcut item.
1949   EXPECT_EQ(1, model_->item_count());
1950   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1951   EXPECT_EQ(nullptr,
1952             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1953 
1954   // Pinning the app should create a new shelf item.
1955   launcher_controller_->PinAppWithID(extension1_->id());
1956   EXPECT_EQ(2, model_->item_count());
1957   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1958   EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[1].status);
1959   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1960   EXPECT_NE(nullptr,
1961             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1962 
1963   // Reporting that the app is running should just update the existing item.
1964   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1965   EXPECT_EQ(2, model_->item_count());
1966   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
1967   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1968   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1969   EXPECT_NE(nullptr,
1970             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1971 
1972   // Unpinning the app should just update the existing item.
1973   launcher_controller_->UnpinAppWithID(extension1_->id());
1974   EXPECT_EQ(2, model_->item_count());
1975   EXPECT_EQ(ash::TYPE_APP, model_->items()[1].type);
1976   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
1977   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1978   EXPECT_NE(nullptr,
1979             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1980 
1981   // Reporting that the app is closed should remove its shelf item.
1982   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1983   EXPECT_EQ(1, model_->item_count());
1984   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1985   EXPECT_EQ(nullptr,
1986             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
1987 }
1988 
1989 // Ensure unpinned V1 app ordering is properly restored after user changes.
TEST_F(ChromeLauncherControllerTest,CheckRunningV1AppOrder)1990 TEST_F(ChromeLauncherControllerTest, CheckRunningV1AppOrder) {
1991   InitLauncherController();
1992 
1993   // The model should only contain the browser shortcut item.
1994   EXPECT_EQ(1, model_->item_count());
1995 
1996   // Add a few running applications.
1997   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1998   launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_RUNNING);
1999   launcher_controller_->SetV1AppStatus(extension_gmail_app_->id(),
2000                                        ash::STATUS_RUNNING);
2001   EXPECT_EQ(4, model_->item_count());
2002   // Note that this not only checks the order of applications but also the
2003   // running type.
2004   EXPECT_EQ("Chrome, app1, app2, gmail", GetPinnedAppStatus());
2005 
2006   // Remember the current order of applications for the current user.
2007   const AccountId& current_account_id =
2008       multi_user_util::GetAccountIdFromProfile(profile());
2009   RememberUnpinnedRunningApplicationOrder();
2010 
2011   // Switch some items and check that restoring a user which was not yet
2012   // remembered changes nothing.
2013   model_->Move(1, 2);
2014   EXPECT_EQ("Chrome, app2, app1, gmail", GetPinnedAppStatus());
2015   const AccountId second_fake_account_id(
2016       AccountId::FromUserEmail("second-fake-user@fake.com"));
2017   RestoreUnpinnedRunningApplicationOrder(second_fake_account_id);
2018   EXPECT_EQ("Chrome, app2, app1, gmail", GetPinnedAppStatus());
2019 
2020   // Restoring the stored user should however do the right thing.
2021   RestoreUnpinnedRunningApplicationOrder(current_account_id);
2022   EXPECT_EQ("Chrome, app1, app2, gmail", GetPinnedAppStatus());
2023 
2024   // Switch again some items and even delete one - making sure that the missing
2025   // item gets properly handled.
2026   model_->Move(2, 3);
2027   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
2028   EXPECT_EQ("Chrome, gmail, app2", GetPinnedAppStatus());
2029   RestoreUnpinnedRunningApplicationOrder(current_account_id);
2030   EXPECT_EQ("Chrome, app2, gmail", GetPinnedAppStatus());
2031 
2032   // Check that removing more items does not crash and changes nothing.
2033   launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_CLOSED);
2034   RestoreUnpinnedRunningApplicationOrder(current_account_id);
2035   EXPECT_EQ("Chrome, gmail", GetPinnedAppStatus());
2036   launcher_controller_->SetV1AppStatus(extension_gmail_app_->id(),
2037                                        ash::STATUS_CLOSED);
2038   RestoreUnpinnedRunningApplicationOrder(current_account_id);
2039   EXPECT_EQ("Chrome", GetPinnedAppStatus());
2040 }
2041 
TEST_F(ChromeLauncherControllerWithArcTest,ArcDeferredLaunch)2042 TEST_F(ChromeLauncherControllerWithArcTest, ArcDeferredLaunch) {
2043   InitLauncherController();
2044 
2045   const arc::mojom::AppInfo& app1 = arc_test_.fake_apps()[0];
2046   const arc::mojom::AppInfo& app2 = arc_test_.fake_apps()[1];
2047   const arc::mojom::AppInfo& gmail = arc_test_.fake_apps()[2];
2048   const arc::mojom::ShortcutInfo& shortcut = arc_test_.fake_shortcuts()[0];
2049   const std::string arc_app_id1 = ArcAppTest::GetAppId(app1);
2050   const std::string arc_app_id2 = ArcAppTest::GetAppId(app2);
2051   const std::string arc_app_id3 = ArcAppTest::GetAppId(gmail);
2052   const std::string arc_shortcut_id = ArcAppTest::GetAppId(shortcut);
2053 
2054   SendListOfArcApps();
2055   SendListOfArcShortcuts();
2056 
2057   arc_test_.StopArcInstance();
2058 
2059   const ash::ShelfID shelf_id_app_1(arc_app_id1);
2060   const ash::ShelfID shelf_id_app_2(arc_app_id2);
2061   const ash::ShelfID shelf_id_app_3(arc_app_id3);
2062   const ash::ShelfID shelf_id_shortcut(arc_shortcut_id);
2063   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_1));
2064   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_2));
2065   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_3));
2066   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_shortcut));
2067 
2068   arc::LaunchApp(profile(), arc_app_id1, ui::EF_LEFT_MOUSE_BUTTON,
2069                  arc::UserInteractionType::NOT_USER_INITIATED);
2070   arc::LaunchApp(profile(), arc_app_id1, ui::EF_LEFT_MOUSE_BUTTON,
2071                  arc::UserInteractionType::NOT_USER_INITIATED);
2072   arc::LaunchApp(profile(), arc_app_id2, ui::EF_LEFT_MOUSE_BUTTON,
2073                  arc::UserInteractionType::NOT_USER_INITIATED);
2074   arc::LaunchApp(profile(), arc_app_id3, ui::EF_LEFT_MOUSE_BUTTON,
2075                  arc::UserInteractionType::NOT_USER_INITIATED);
2076   arc::LaunchApp(profile(), arc_shortcut_id, ui::EF_LEFT_MOUSE_BUTTON,
2077                  arc::UserInteractionType::NOT_USER_INITIATED);
2078 
2079   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_app_1));
2080   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_app_2));
2081   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_app_3));
2082   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_shortcut));
2083 
2084   // We activated arc_app_id1 twice but expect one close for item controller
2085   // stops launching request.
2086   ash::ShelfItemDelegate* item_delegate =
2087       model_->GetShelfItemDelegate(shelf_id_app_1);
2088   ASSERT_NE(nullptr, item_delegate);
2089   item_delegate->Close();
2090   base::RunLoop().RunUntilIdle();
2091 
2092   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_1));
2093   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_app_2));
2094   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_app_3));
2095   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id_shortcut));
2096 
2097   arc_test_.RestartArcInstance();
2098   SendListOfArcApps();
2099 
2100   base::RunLoop().RunUntilIdle();
2101 
2102   // Now spinner controllers should go away together with shelf items and ARC
2103   // app instance should receive request for launching apps and shortcuts.
2104   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_1));
2105   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_2));
2106   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_app_3));
2107   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id_shortcut));
2108 
2109   ASSERT_EQ(2U, arc_test_.app_instance()->launch_requests().size());
2110   ASSERT_EQ(1U, arc_test_.app_instance()->launch_intents().size());
2111 
2112   const arc::FakeAppInstance::Request* request1 =
2113       arc_test_.app_instance()->launch_requests()[0].get();
2114   const arc::FakeAppInstance::Request* request2 =
2115       arc_test_.app_instance()->launch_requests()[1].get();
2116 
2117   EXPECT_TRUE((request1->IsForApp(app2) && request2->IsForApp(gmail)) ||
2118               (request1->IsForApp(gmail) && request2->IsForApp(app2)));
2119   EXPECT_EQ(arc_test_.app_instance()->launch_intents()[0].c_str(),
2120             shortcut.intent_uri);
2121 }
2122 
2123 // Launch is canceled in case app becomes suspended.
TEST_F(ChromeLauncherControllerWithArcTest,ArcDeferredLaunchForSuspendedApp)2124 TEST_F(ChromeLauncherControllerWithArcTest, ArcDeferredLaunchForSuspendedApp) {
2125   InitLauncherController();
2126 
2127   arc::mojom::AppInfo app = arc_test_.fake_apps()[0];
2128   const std::string app_id = ArcAppTest::GetAppId(app);
2129 
2130   // Register app first.
2131   arc_test_.app_instance()->SendRefreshAppList({app});
2132   arc_test_.StopArcInstance();
2133 
2134   // Restart ARC
2135   arc_test_.RestartArcInstance();
2136 
2137   // Deferred controller should be allocated on start.
2138   const ash::ShelfID shelf_id(app_id);
2139   arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON,
2140                  arc::UserInteractionType::NOT_USER_INITIATED);
2141   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
2142 
2143   // Send app with suspended state.
2144   app.suspended = true;
2145   arc_test_.app_instance()->SendRefreshAppList({app});
2146 
2147   // Controler automatically closed.
2148   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
2149 
2150   // And no launch request issued.
2151   EXPECT_TRUE(arc_test_.app_instance()->launch_requests().empty());
2152 }
2153 
2154 // Ensure the spinner controller does not override the active app controller
2155 // (crbug.com/701152).
TEST_F(ChromeLauncherControllerWithArcTest,ArcDeferredLaunchForActiveApp)2156 TEST_F(ChromeLauncherControllerWithArcTest, ArcDeferredLaunchForActiveApp) {
2157   InitLauncherController();
2158   SendListOfArcApps();
2159   arc_test_.StopArcInstance();
2160 
2161   const arc::mojom::AppInfo& app = arc_test_.fake_apps()[0];
2162   const std::string app_id = ArcAppTest::GetAppId(app);
2163 
2164   launcher_controller_->PinAppWithID(app_id);
2165   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
2166   const ash::ShelfID shelf_id(app_id);
2167   const ash::ShelfItem* item = launcher_controller_->GetItem(shelf_id);
2168   ASSERT_NE(nullptr, item);
2169   EXPECT_EQ(ash::STATUS_CLOSED, item->status);
2170   EXPECT_EQ(ash::TYPE_PINNED_APP, item->type);
2171 
2172   // Play Store app is ARC app that might be represented by native Chrome
2173   // platform app.
2174   model_->SetShelfItemDelegate(
2175       shelf_id,
2176       std::make_unique<AppServiceAppWindowLauncherItemController>(
2177           shelf_id, launcher_controller_->app_service_app_window_controller()));
2178   launcher_controller_->SetItemStatus(shelf_id, ash::STATUS_RUNNING);
2179 
2180   // This launch request should be ignored in case of active app.
2181   arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON,
2182                  arc::UserInteractionType::NOT_USER_INITIATED);
2183   EXPECT_FALSE(
2184       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
2185 
2186   // Closing the app should leave a pinned but closed shelf item shortcut.
2187   launcher_controller_->CloseLauncherItem(shelf_id);
2188   item = launcher_controller_->GetItem(shelf_id);
2189   ASSERT_NE(nullptr, item);
2190   EXPECT_EQ(ash::STATUS_CLOSED, item->status);
2191   EXPECT_EQ(ash::TYPE_PINNED_APP, item->type);
2192 
2193   // Now launch request should not be ignored.
2194   arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON,
2195                  arc::UserInteractionType::NOT_USER_INITIATED);
2196   EXPECT_TRUE(
2197       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
2198 }
2199 
2200 // TODO(crbug.com/915840): this test is flakey and/or often crashes.
TEST_F(ChromeLauncherControllerMultiProfileWithArcTest,DISABLED_ArcMultiUser)2201 TEST_F(ChromeLauncherControllerMultiProfileWithArcTest, DISABLED_ArcMultiUser) {
2202   SendListOfArcApps();
2203 
2204   InitLauncherController();
2205 
2206   SetLauncherControllerHelper(new TestLauncherControllerHelper);
2207 
2208   // App1 exists all the time.
2209   // App2 is created when primary user is active and destroyed when secondary
2210   // user is active.
2211   // Gmail created when secondary user is active.
2212 
2213   const std::string user2 = "user2";
2214   TestingProfile* profile2 = CreateMultiUserProfile(user2);
2215   const AccountId account_id(
2216       multi_user_util::GetAccountIdFromProfile(profile()));
2217   const AccountId account_id2(
2218       multi_user_util::GetAccountIdFromProfile(profile2));
2219 
2220   const std::string arc_app_id1 =
2221       ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2222   const std::string arc_app_id2 =
2223       ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
2224   const std::string arc_app_id3 =
2225       ArcAppTest::GetAppId(arc_test_.fake_apps()[2]);
2226 
2227   std::string window_app_id1("org.chromium.arc.1");
2228   views::Widget* arc_window1 = CreateArcWindow(window_app_id1);
2229   arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2230                                             std::string());
2231   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2232 
2233   std::string window_app_id2("org.chromium.arc.2");
2234   views::Widget* arc_window2 = CreateArcWindow(window_app_id2);
2235   arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1],
2236                                             std::string());
2237   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2238 
2239   launcher_controller_->SetProfileForTest(profile2);
2240   SwitchActiveUser(account_id2);
2241 
2242   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2243   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2244 
2245   std::string window_app_id3("org.chromium.arc.3");
2246   views::Widget* arc_window3 = CreateArcWindow(window_app_id3);
2247   arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[2],
2248                                             std::string());
2249   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id3)));
2250 
2251   arc_window2->CloseNow();
2252   arc_test_.app_instance()->SendTaskDestroyed(2);
2253 
2254   launcher_controller_->SetProfileForTest(profile());
2255   SwitchActiveUser(account_id);
2256 
2257   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2258   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2259   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id3)));
2260 
2261   // Close active window to let test passes.
2262   arc_window1->CloseNow();
2263   arc_window3->CloseNow();
2264 }
2265 
TEST_F(ChromeLauncherControllerWithArcTest,ArcRunningApp)2266 TEST_F(ChromeLauncherControllerWithArcTest, ArcRunningApp) {
2267   InitLauncherController();
2268 
2269   const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2270   SendListOfArcApps();
2271   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2272 
2273   // Normal flow, create/destroy tasks.
2274   std::string window_app_id1("org.chromium.arc.1");
2275   std::string window_app_id2("org.chromium.arc.2");
2276   std::string window_app_id3("org.chromium.arc.3");
2277   CreateArcWindow(window_app_id1);
2278   arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2279                                             std::string());
2280   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2281   CreateArcWindow(window_app_id2);
2282   arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[0],
2283                                             std::string());
2284   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2285   arc_test_.app_instance()->SendTaskDestroyed(1);
2286   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2287   arc_test_.app_instance()->SendTaskDestroyed(2);
2288   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2289 
2290   // Stopping bridge removes apps.
2291   CreateArcWindow(window_app_id3);
2292   arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[0],
2293                                             std::string());
2294   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2295   arc_test_.StopArcInstance();
2296   base::RunLoop().RunUntilIdle();
2297   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2298 }
2299 
2300 // Test race creation/deletion of ARC app.
2301 // TODO(khmel): Remove after moving everything to wayland protocol.
TEST_F(ChromeLauncherControllerWithArcTest,ArcRaceCreateClose)2302 TEST_F(ChromeLauncherControllerWithArcTest, ArcRaceCreateClose) {
2303   InitLauncherController();
2304 
2305   const std::string arc_app_id1 =
2306       ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2307   const std::string arc_app_id2 =
2308       ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
2309   SendListOfArcApps();
2310 
2311   // ARC window created before and closed after mojom notification.
2312   std::string window_app_id1("org.chromium.arc.1");
2313   views::Widget* arc_window = CreateArcWindow(window_app_id1);
2314   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2315   ASSERT_TRUE(arc_window);
2316   arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2317                                             std::string());
2318   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2319   arc_test_.app_instance()->SendTaskDestroyed(1);
2320   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2321   arc_window->Close();
2322   base::RunLoop().RunUntilIdle();
2323   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id1)));
2324 
2325   // ARC window created after and closed before mojom notification.
2326   std::string window_app_id2("org.chromium.arc.2");
2327   arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1],
2328                                             std::string());
2329   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2330   arc_window = CreateArcWindow(window_app_id2);
2331   ASSERT_TRUE(arc_window);
2332   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2333   arc_window->Close();
2334   base::RunLoop().RunUntilIdle();
2335   // Closing window does not close shelf item. It is closed on task destroy.
2336   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2337   arc_test_.app_instance()->SendTaskDestroyed(2);
2338   EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id2)));
2339 }
2340 
TEST_F(ChromeLauncherControllerWithArcTest,ArcWindowRecreation)2341 TEST_F(ChromeLauncherControllerWithArcTest, ArcWindowRecreation) {
2342   InitLauncherController();
2343 
2344   const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2345   SendListOfArcApps();
2346 
2347   std::string window_app_id("org.chromium.arc.1");
2348   views::Widget* arc_window = CreateArcWindow(window_app_id);
2349   ASSERT_TRUE(arc_window);
2350   arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2351                                             std::string());
2352   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2353 
2354   for (int i = 0; i < 3; ++i) {
2355     arc_window->Close();
2356     base::RunLoop().RunUntilIdle();
2357     EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2358 
2359     arc_window = CreateArcWindow(window_app_id);
2360     ASSERT_TRUE(arc_window);
2361     base::RunLoop().RunUntilIdle();
2362     EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
2363   }
2364 }
2365 
2366 // Verifies edge cases when Extension app launcher may be overwritten by ARC app
2367 // launcher controller and vice versa. This should not happen in normal cases
2368 // but in case of ARC boot failure this may lead to such situation. This test
2369 // verifies that dynamic change of app launcher controllers is safe.
2370 // See more crbug.com/770005.
TEST_F(ChromeLauncherControllerWithArcTest,OverrideAppItemController)2371 TEST_F(ChromeLauncherControllerWithArcTest, OverrideAppItemController) {
2372   extension_service_->AddExtension(arc_support_host_.get());
2373 
2374   InitLauncherController();
2375 
2376   SendListOfArcApps();
2377   arc::mojom::AppInfo app_info = CreateAppInfo(
2378       "Play Store", arc::kPlayStoreActivity, arc::kPlayStorePackage);
2379   EXPECT_EQ(arc::kPlayStoreAppId, AddArcAppAndShortcut(app_info));
2380   app_service_test().WaitForAppService();
2381 
2382   std::string window_app_id("org.chromium.arc.1");
2383   const ash::ShelfID play_store_shelf_id(arc::kPlayStoreAppId);
2384 
2385   launcher_controller_->UnpinAppWithID(arc::kPlayStoreAppId);
2386   EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2387 
2388   // Try 4 different scenarios with different creation and destroying orders.
2389 
2390   // Scenario 1: Create OptIn, Play Store. Destroy OptIn, Play Store.
2391   {
2392     std::unique_ptr<V2App> play_store_optin =
2393         std::make_unique<V2App>(profile(), arc_support_host_.get(),
2394                                 extensions::AppWindow::WINDOW_TYPE_DEFAULT);
2395     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2396 
2397     views::Widget* arc_window = CreateArcWindow(window_app_id);
2398     ASSERT_TRUE(arc_window);
2399     arc_test_.app_instance()->SendTaskCreated(1, app_info, std::string());
2400     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2401 
2402     play_store_optin.reset();
2403     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2404 
2405     arc_window->CloseNow();
2406     arc_test_.app_instance()->SendTaskDestroyed(1);
2407     EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2408   }
2409 
2410   // Scenario 2: Create OptIn, Play Store. Destroy Play Store, OptIn.
2411   {
2412     std::unique_ptr<V2App> play_store_optin =
2413         std::make_unique<V2App>(profile(), arc_support_host_.get(),
2414                                 extensions::AppWindow::WINDOW_TYPE_DEFAULT);
2415     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2416 
2417     views::Widget* arc_window = CreateArcWindow(window_app_id);
2418     ASSERT_TRUE(arc_window);
2419     arc_test_.app_instance()->SendTaskCreated(1, app_info, std::string());
2420     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2421 
2422     arc_window->CloseNow();
2423     arc_test_.app_instance()->SendTaskDestroyed(1);
2424     EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2425 
2426     play_store_optin.reset();
2427     EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2428   }
2429 
2430   // Scenario 3: Create Play Store, OptIn. Destroy OptIn, Play Store.
2431   {
2432     views::Widget* arc_window = CreateArcWindow(window_app_id);
2433     ASSERT_TRUE(arc_window);
2434     arc_test_.app_instance()->SendTaskCreated(1, app_info, std::string());
2435     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2436 
2437     std::unique_ptr<V2App> play_store_optin =
2438         std::make_unique<V2App>(profile(), arc_support_host_.get(),
2439                                 extensions::AppWindow::WINDOW_TYPE_DEFAULT);
2440     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2441 
2442     play_store_optin.reset();
2443     EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2444 
2445     arc_window->CloseNow();
2446     arc_test_.app_instance()->SendTaskDestroyed(1);
2447     EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2448   }
2449 
2450   // Scenario 4: Create Play Store, OptIn. Destroy Play Store, OptIn.
2451   {
2452     views::Widget* arc_window = CreateArcWindow(window_app_id);
2453     ASSERT_TRUE(arc_window);
2454     arc_test_.app_instance()->SendTaskCreated(1, app_info, std::string());
2455     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2456 
2457     std::unique_ptr<V2App> play_store_optin =
2458         std::make_unique<V2App>(profile(), arc_support_host_.get(),
2459                                 extensions::AppWindow::WINDOW_TYPE_DEFAULT);
2460     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2461 
2462     arc_window->CloseNow();
2463     arc_test_.app_instance()->SendTaskDestroyed(1);
2464     EXPECT_TRUE(launcher_controller_->GetItem(play_store_shelf_id));
2465 
2466     play_store_optin.reset();
2467     EXPECT_FALSE(launcher_controller_->GetItem(play_store_shelf_id));
2468   }
2469 }
2470 
2471 // Validate that ARC app is pinned correctly and pin is removed automatically
2472 // once app is uninstalled.
TEST_F(ChromeLauncherControllerWithArcTest,ArcAppPin)2473 TEST_F(ChromeLauncherControllerWithArcTest, ArcAppPin) {
2474   InitLauncherController();
2475 
2476   const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2477 
2478   SendListOfArcApps();
2479   extension_service_->AddExtension(extension1_.get());
2480   extension_service_->AddExtension(extension2_.get());
2481   // Allow async callbacks to run.
2482   base::RunLoop().RunUntilIdle();
2483 
2484   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
2485   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id));
2486   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
2487 
2488   launcher_controller_->PinAppWithID(extension1_->id());
2489   launcher_controller_->PinAppWithID(arc_app_id);
2490   launcher_controller_->PinAppWithID(extension2_->id());
2491 
2492   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2493   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id));
2494   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2495 
2496   EXPECT_EQ("Chrome, App1, Fake App 0, App2", GetPinnedAppStatus());
2497 
2498   UninstallArcApps();
2499   // Allow async callbacks to run.
2500   base::RunLoop().RunUntilIdle();
2501 
2502   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id));
2503   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
2504 
2505   SendListOfArcApps();
2506   // Allow async callbacks to run.
2507   base::RunLoop().RunUntilIdle();
2508 
2509   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id));
2510   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
2511 
2512   // Opt-Out/Opt-In remove item from the shelf.
2513   launcher_controller_->PinAppWithID(arc_app_id);
2514   EXPECT_EQ("Chrome, App1, App2, Fake App 0", GetPinnedAppStatus());
2515   EnablePlayStore(false);
2516   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
2517   EnablePlayStore(true);
2518   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
2519 
2520   SendListOfArcApps();
2521   // Allow async callbacks to run.
2522   base::RunLoop().RunUntilIdle();
2523 
2524   EXPECT_EQ("Chrome, App1, App2, Fake App 0", GetPinnedAppStatus());
2525 }
2526 
2527 // Validates that ARC app pins persist across OptOut/OptIn.
TEST_F(ChromeLauncherControllerWithArcTest,ArcAppPinOptOutOptIn)2528 TEST_F(ChromeLauncherControllerWithArcTest, ArcAppPinOptOutOptIn) {
2529   InitLauncherController();
2530 
2531   const std::string arc_app_id1 =
2532       ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2533   const std::string arc_app_id2 =
2534       ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
2535 
2536   SendListOfArcApps();
2537   extension_service_->AddExtension(extension1_.get());
2538   extension_service_->AddExtension(extension2_.get());
2539 
2540   launcher_controller_->PinAppWithID(extension1_->id());
2541   launcher_controller_->PinAppWithID(arc_app_id2);
2542   launcher_controller_->PinAppWithID(extension2_->id());
2543   launcher_controller_->PinAppWithID(arc_app_id1);
2544 
2545   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2546   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
2547   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2548   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
2549   EXPECT_EQ("Chrome, App1, Fake App 1, App2, Fake App 0", GetPinnedAppStatus());
2550 
2551   EnablePlayStore(false);
2552 
2553   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
2554   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2555   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
2556   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2557   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
2558 
2559   EnablePlayStore(true);
2560   SendListOfArcApps();
2561   base::RunLoop().RunUntilIdle();
2562 
2563   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2564   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
2565   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2566   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
2567 
2568   EXPECT_EQ("Chrome, App1, Fake App 1, App2, Fake App 0", GetPinnedAppStatus());
2569 }
2570 
TEST_F(ChromeLauncherControllerWithArcTest,DISABLED_ArcCustomAppIcon)2571 TEST_F(ChromeLauncherControllerWithArcTest, DISABLED_ArcCustomAppIcon) {
2572   InitLauncherController();
2573 
2574   // Wait until other apps are updated to avoid race condition while accessing
2575   // last updated item.
2576   base::RunLoop().RunUntilIdle();
2577 
2578   // Register fake ARC apps.
2579   SendListOfArcApps();
2580   // Use first fake ARC app for testing.
2581   const arc::mojom::AppInfo& app = arc_test_.fake_apps()[0];
2582   const std::string arc_app_id = ArcAppTest::GetAppId(app);
2583   const ash::ShelfID arc_shelf_id(arc_app_id);
2584 
2585   // Generate icon for the testing app and use compressed png content as test
2586   // input. Take shortcut to separate from default app icon.
2587   auto icon = arc_test_.app_instance()->GenerateIconResponse(
2588       extension_misc::EXTENSION_ICON_SMALL, false /* app_icon */);
2589   ASSERT_TRUE(icon);
2590   ASSERT_TRUE(icon->icon_png_data.has_value());
2591   EXPECT_FALSE(icon->icon_png_data->empty());
2592   std::string png_data(icon->icon_png_data->begin(),
2593                        icon->icon_png_data->end());
2594   // Some input that represents invalid png content.
2595   std::string invalid_png_data("aaaaaa");
2596 
2597   EXPECT_FALSE(launcher_controller_->GetItem(arc_shelf_id));
2598   std::string window_app_id1("org.chromium.arc.1");
2599   std::string window_app_id2("org.chromium.arc.2");
2600   views::Widget* window1 = CreateArcWindow(window_app_id1);
2601   ASSERT_TRUE(window1 && window1->GetNativeWindow());
2602   arc_test_.app_instance()->SendTaskCreated(1, app, std::string());
2603 
2604   views::Widget* window2 = CreateArcWindow(window_app_id2);
2605   ASSERT_TRUE(window2 && window2->GetNativeWindow());
2606   arc_test_.app_instance()->SendTaskCreated(2, app, std::string());
2607   EXPECT_TRUE(launcher_controller_->GetItem(arc_shelf_id));
2608   ash::ShelfItemDelegate* item_delegate =
2609       model_->GetShelfItemDelegate(arc_shelf_id);
2610   ASSERT_TRUE(item_delegate);
2611   base::RunLoop().RunUntilIdle();
2612 
2613   auto get_icon = [=]() {
2614     return *launcher_controller_->GetItem(arc_shelf_id)->image.bitmap();
2615   };
2616   const SkBitmap default_icon = get_icon();
2617 
2618   // No custom icon set. Acitivating windows should not change icon.
2619   window1->Activate();
2620   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon, get_icon()));
2621   window2->Activate();
2622   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon, get_icon()));
2623 
2624   // Set custom icon on active item. Icon should change to custom.
2625   arc_test_.app_instance()->SendTaskDescription(2, std::string(), png_data);
2626   const SkBitmap custom_icon = get_icon();
2627   EXPECT_FALSE(gfx::test::AreBitmapsEqual(default_icon, custom_icon));
2628 
2629   // Switch back to the item without custom icon. Icon should be changed to
2630   // default.
2631   window1->Activate();
2632   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon, get_icon()));
2633 
2634   // Test that setting an invalid icon should not change custom icon.
2635   arc_test_.app_instance()->SendTaskDescription(1, std::string(), png_data);
2636   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon, get_icon()));
2637   arc_test_.app_instance()->SendTaskDescription(1, std::string(),
2638                                                 invalid_png_data);
2639   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon, get_icon()));
2640 
2641   // Check window removing with active custom icon. Reseting custom icon of
2642   // inactive window doesn't reset shelf icon.
2643   arc_test_.app_instance()->SendTaskDescription(2, std::string(),
2644                                                 std::string());
2645   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon, get_icon()));
2646   // Set custom icon back to validate closing active window later.
2647   arc_test_.app_instance()->SendTaskDescription(2, std::string(), png_data);
2648   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon, get_icon()));
2649 
2650   // Reseting custom icon of active window resets shelf icon.
2651   arc_test_.app_instance()->SendTaskDescription(1, std::string(),
2652                                                 std::string());
2653   // Wait for default icon load.
2654   base::RunLoop().RunUntilIdle();
2655   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon, get_icon()));
2656   window1->CloseNow();
2657   EXPECT_TRUE(gfx::test::AreBitmapsEqual(custom_icon, get_icon()));
2658 }
2659 
TEST_F(ChromeLauncherControllerWithArcTest,ArcWindowPackageName)2660 TEST_F(ChromeLauncherControllerWithArcTest, ArcWindowPackageName) {
2661   InitLauncherController();
2662   SendListOfArcApps();
2663   app_service_test().WaitForAppService();
2664 
2665   std::string window_app_id1("org.chromium.arc.1");
2666   std::string window_app_id2("org.chromium.arc.2");
2667   std::string window_app_id3("org.chromium.arc.3");
2668   views::Widget* arc_window1 = CreateArcWindow(window_app_id1);
2669   arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2670                                             std::string());
2671   const std::string* package_name1 =
2672       arc_window1->GetNativeWindow()->GetProperty(ash::kArcPackageNameKey);
2673   ASSERT_TRUE(package_name1);
2674   EXPECT_EQ(*package_name1, arc_test_.fake_apps()[0].package_name);
2675 
2676   views::Widget* arc_window2 = CreateArcWindow(window_app_id2);
2677   arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1],
2678                                             std::string());
2679   const std::string* package_name2 =
2680       arc_window2->GetNativeWindow()->GetProperty(ash::kArcPackageNameKey);
2681   ASSERT_TRUE(package_name2);
2682   EXPECT_EQ(*package_name2, arc_test_.fake_apps()[1].package_name);
2683 
2684   // Create another window with the same package name.
2685   views::Widget* arc_window3 = CreateArcWindow(window_app_id3);
2686   arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[1],
2687                                             std::string());
2688   const std::string* package_name3 =
2689       arc_window3->GetNativeWindow()->GetProperty(ash::kArcPackageNameKey);
2690   ASSERT_TRUE(package_name3);
2691   EXPECT_EQ(*package_name3, arc_test_.fake_apps()[1].package_name);
2692 
2693   arc_window1->CloseNow();
2694   arc_window2->CloseNow();
2695   arc_window3->CloseNow();
2696 }
2697 
2698 // Check that with multi profile V1 apps are properly added / removed from the
2699 // shelf.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V1AppUpdateOnUserSwitch)2700 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2701        V1AppUpdateOnUserSwitch) {
2702   // Create a browser item in the LauncherController.
2703   InitLauncherController();
2704 
2705   EXPECT_EQ(1, model_->item_count());
2706   {
2707     // Create a "windowed gmail app".
2708     std::unique_ptr<V1App> v1_app(
2709         CreateRunningV1App(profile(), extension_misc::kGmailAppId, kGmailUrl));
2710     EXPECT_EQ(2, model_->item_count());
2711 
2712     // After switching to a second user the item should be gone.
2713     std::string user2 = "user2";
2714     TestingProfile* profile2 = CreateMultiUserProfile(user2);
2715     const AccountId account_id2(
2716         multi_user_util::GetAccountIdFromProfile(profile2));
2717     const AccountId account_id(
2718         multi_user_util::GetAccountIdFromProfile(profile()));
2719     SwitchActiveUser(account_id2);
2720     EXPECT_EQ(1, model_->item_count());
2721 
2722     // After switching back the item should be back.
2723     SwitchActiveUser(account_id);
2724     EXPECT_EQ(2, model_->item_count());
2725     // Note we destroy now the gmail app with the closure end.
2726   }
2727   EXPECT_EQ(1, model_->item_count());
2728 }
2729 
2730 // Check edge cases with multi profile V1 apps in the shelf.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V1AppUpdateOnUserSwitchEdgecases)2731 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2732        V1AppUpdateOnUserSwitchEdgecases) {
2733   // Create a browser item in the LauncherController.
2734   InitLauncherController();
2735 
2736   // First test: Create an app when the user is not active.
2737   std::string user2 = "user2";
2738   TestingProfile* profile2 = CreateMultiUserProfile(user2);
2739   const AccountId account_id2(
2740       multi_user_util::GetAccountIdFromProfile(profile2));
2741   const AccountId account_id(
2742       multi_user_util::GetAccountIdFromProfile(profile()));
2743   {
2744     // Create a "windowed gmail app".
2745     std::unique_ptr<V1App> v1_app(
2746         CreateRunningV1App(profile2, extension_misc::kGmailAppId, kGmailUrl));
2747     EXPECT_EQ(1, model_->item_count());
2748 
2749     // However - switching to the user should show it.
2750     SwitchActiveUser(account_id2);
2751     EXPECT_EQ(2, model_->item_count());
2752 
2753     // Second test: Remove the app when the user is not active and see that it
2754     // works.
2755     SwitchActiveUser(account_id);
2756     EXPECT_EQ(1, model_->item_count());
2757     // Note: the closure ends and the browser will go away.
2758   }
2759   EXPECT_EQ(1, model_->item_count());
2760   SwitchActiveUser(account_id2);
2761   EXPECT_EQ(1, model_->item_count());
2762   SwitchActiveUser(account_id);
2763   EXPECT_EQ(1, model_->item_count());
2764 }
2765 
2766 // Check edge case where a visiting V1 app gets closed (crbug.com/321374).
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V1CloseOnVisitingDesktop)2767 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2768        V1CloseOnVisitingDesktop) {
2769   // Create a browser item in the LauncherController.
2770   InitLauncherController();
2771 
2772   // First create an app when the user is active.
2773   std::string user2 = "user2";
2774   TestingProfile* profile2 = CreateMultiUserProfile(user2);
2775   const AccountId account_id(
2776       multi_user_util::GetAccountIdFromProfile(profile()));
2777   const AccountId account_id2(
2778       multi_user_util::GetAccountIdFromProfile(profile2));
2779   {
2780     // Create a "windowed gmail app".
2781     std::unique_ptr<V1App> v1_app(CreateRunningV1App(
2782         profile(), extension_misc::kGmailAppId, kGmailLaunchURL));
2783     EXPECT_EQ(2, model_->item_count());
2784     SwitchActiveUser(account_id2);
2785     EXPECT_EQ(1, model_->item_count());
2786   }
2787   // After the app was destroyed, switch back. (which caused already a crash).
2788   SwitchActiveUser(account_id);
2789 
2790   // Create the same app again - which was also causing the crash.
2791   EXPECT_EQ(1, model_->item_count());
2792   {
2793     // Create a "windowed gmail app".
2794     std::unique_ptr<V1App> v1_app(CreateRunningV1App(
2795         profile(), extension_misc::kGmailAppId, kGmailLaunchURL));
2796     EXPECT_EQ(2, model_->item_count());
2797   }
2798   SwitchActiveUser(account_id2);
2799   EXPECT_EQ(1, model_->item_count());
2800 }
2801 
2802 // Check edge cases with multi profile V1 apps in the shelf.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V1AppUpdateOnUserSwitchEdgecases2)2803 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2804        V1AppUpdateOnUserSwitchEdgecases2) {
2805   // Create a browser item in the LauncherController.
2806   InitLauncherController();
2807 
2808   // First test: Create an app when the user is not active.
2809   std::string user2 = "user2";
2810   TestingProfile* profile2 = CreateMultiUserProfile(user2);
2811   const AccountId account_id(
2812       multi_user_util::GetAccountIdFromProfile(profile()));
2813   const AccountId account_id2(
2814       multi_user_util::GetAccountIdFromProfile(profile2));
2815   SwitchActiveUser(account_id2);
2816   {
2817     // Create a "windowed gmail app".
2818     std::unique_ptr<V1App> v1_app(
2819         CreateRunningV1App(profile(), extension_misc::kGmailAppId, kGmailUrl));
2820     EXPECT_EQ(1, model_->item_count());
2821 
2822     // However - switching to the user should show it.
2823     SwitchActiveUser(account_id);
2824     EXPECT_EQ(2, model_->item_count());
2825 
2826     // Second test: Remove the app when the user is not active and see that it
2827     // works.
2828     SwitchActiveUser(account_id2);
2829     EXPECT_EQ(1, model_->item_count());
2830     v1_app.reset();
2831   }
2832   EXPECT_EQ(1, model_->item_count());
2833   SwitchActiveUser(account_id);
2834   EXPECT_EQ(1, model_->item_count());
2835   SwitchActiveUser(account_id2);
2836   EXPECT_EQ(1, model_->item_count());
2837 }
2838 
2839 // Check that activating an item which is on another user's desktop, will bring
2840 // it back.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,TestLauncherActivationPullsBackWindow)2841 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2842        TestLauncherActivationPullsBackWindow) {
2843   // Create a browser item in the LauncherController.
2844   InitLauncherController();
2845   ash::MultiUserWindowManager* window_manager =
2846       MultiUserWindowManagerHelper::GetWindowManager();
2847 
2848   // Create a second test profile. The first is the one in profile() created in
2849   // BrowserWithTestWindowTest::SetUp().
2850   // No need to add the profiles to the MultiUserWindowManagerHelper here.
2851   // CreateMultiUserProfile() already does that.
2852   TestingProfile* profile2 = CreateMultiUserProfile("user2");
2853   const AccountId current_user =
2854       multi_user_util::GetAccountIdFromProfile(profile());
2855 
2856   // Create a browser window with a native window for the current user.
2857   std::unique_ptr<Browser> browser(
2858       CreateBrowserWithTestWindowForProfile(profile()));
2859   BrowserWindow* browser_window = browser->window();
2860   aura::Window* window = browser_window->GetNativeWindow();
2861   window_manager->SetWindowOwner(window, current_user);
2862 
2863   // Check that an activation of the window on its owner's desktop does not
2864   // change the visibility to another user.
2865   launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false);
2866   EXPECT_TRUE(IsWindowOnDesktopOfUser(window, current_user));
2867 
2868   // Transfer the window to another user's desktop and check that activating it
2869   // does pull it back to that user.
2870   window_manager->ShowWindowForUser(
2871       window, multi_user_util::GetAccountIdFromProfile(profile2));
2872   EXPECT_FALSE(IsWindowOnDesktopOfUser(window, current_user));
2873   launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false);
2874   EXPECT_TRUE(IsWindowOnDesktopOfUser(window, current_user));
2875 }
2876 
2877 // Check that a running windowed V1 application will be properly pinned and
2878 // unpinned when the order gets changed through a profile / policy change.
TEST_F(ChromeLauncherControllerTest,RestoreDefaultAndRunningV1AppsResyncOrder)2879 TEST_F(ChromeLauncherControllerTest,
2880        RestoreDefaultAndRunningV1AppsResyncOrder) {
2881   InitLauncherController();
2882 
2883   StartPrefSyncService(syncer::SyncDataList());
2884 
2885   syncer::SyncChangeList sync_list;
2886   InsertAddPinChange(&sync_list, 0, extension1_->id());
2887   InsertAddPinChange(&sync_list, 1, extension_gmail_app_->id());
2888   SendPinChanges(sync_list, true);
2889 
2890   // The shelf layout has always one static item at the beginning (App List).
2891   AddExtension(extension1_.get());
2892   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
2893   AddExtension(extension2_.get());
2894   // No new app icon will be generated.
2895   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
2896 
2897   // Set the app status as running, which will add an unpinned item.
2898   launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_RUNNING);
2899   EXPECT_EQ("Chrome, App1, app2", GetPinnedAppStatus());
2900   AddExtension(extension_gmail_app_.get());
2901   EXPECT_EQ("Chrome, App1, Gmail, app2", GetPinnedAppStatus());
2902 
2903   // Now request to pin all items, which will pin the running unpinned items.
2904   syncer::SyncChangeList sync_list1;
2905   InsertAddPinChange(&sync_list1, 0, extension_gmail_app_->id());
2906   InsertAddPinChange(&sync_list1, 1, extension2_->id());
2907   InsertAddPinChange(&sync_list1, 2, extension1_->id());
2908   SendPinChanges(sync_list1, true);
2909   EXPECT_EQ("Chrome, Gmail, App2, App1", GetPinnedAppStatus());
2910 
2911   // Removing the requirement for app 2 to be pinned should convert it back to
2912   // running but not pinned. It should move towards the end of the shelf, after
2913   // the pinned items, as determined by the |ShelfModel|'s weight system.
2914   syncer::SyncChangeList sync_list2;
2915   InsertAddPinChange(&sync_list2, 0, extension_gmail_app_->id());
2916   InsertAddPinChange(&sync_list2, 1, extension1_->id());
2917   SendPinChanges(sync_list2, true);
2918   EXPECT_EQ("Chrome, Gmail, App1, app2", GetPinnedAppStatus());
2919 
2920   // Removing an item should simply close it and everything should shift.
2921   syncer::SyncChangeList sync_list3;
2922   InsertRemovePinChange(&sync_list3, extension1_->id());
2923   SendPinChanges(sync_list3, false /* reset_pin_model */);
2924   EXPECT_EQ("Chrome, Gmail, app2", GetPinnedAppStatus());
2925 }
2926 
2927 // Check that a running unpinned V2 application will be properly pinned and
2928 // unpinned when the order gets changed through a profile / policy change.
TEST_F(ChromeLauncherControllerTest,RestoreDefaultAndRunningV2AppsResyncOrder)2929 TEST_F(ChromeLauncherControllerTest,
2930        RestoreDefaultAndRunningV2AppsResyncOrder) {
2931   InitLauncherController();
2932   syncer::SyncChangeList sync_list0;
2933   InsertAddPinChange(&sync_list0, 0, extension1_->id());
2934   InsertAddPinChange(&sync_list0, 1, extension_gmail_app_->id());
2935   SendPinChanges(sync_list0, true);
2936   // The shelf layout has always one static item at the beginning (app List).
2937   AddExtension(extension1_.get());
2938   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
2939   AddExtension(extension_platform_app_.get());
2940   // No new app icon will be generated.
2941   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
2942   // Add an unpinned but running V2 app.
2943   CreateRunningV2App(extension_platform_app_->id());
2944   EXPECT_EQ("Chrome, App1, *platform_app", GetPinnedAppStatus());
2945   AddExtension(extension_gmail_app_.get());
2946   EXPECT_EQ("Chrome, App1, Gmail, *platform_app", GetPinnedAppStatus());
2947 
2948   // Now request to pin all items, which should pin the running unpinned item.
2949   syncer::SyncChangeList sync_list1;
2950   InsertAddPinChange(&sync_list1, 0, extension_gmail_app_->id());
2951   InsertAddPinChange(&sync_list1, 1, extension_platform_app_->id());
2952   InsertAddPinChange(&sync_list1, 2, extension1_->id());
2953   SendPinChanges(sync_list1, true);
2954   EXPECT_EQ("Chrome, Gmail, *Platform_App, App1", GetPinnedAppStatus());
2955 
2956   // Removing the requirement for app 2 to be pinned should convert it back to
2957   // running but not pinned. It should move towards the end of the shelf, after
2958   // the pinned items, as determined by the |ShelfModel|'s weight system.
2959   syncer::SyncChangeList sync_list2;
2960   InsertAddPinChange(&sync_list2, 0, extension_gmail_app_->id());
2961   InsertAddPinChange(&sync_list2, 1, extension1_->id());
2962   SendPinChanges(sync_list2, true);
2963   EXPECT_EQ("Chrome, Gmail, App1, *platform_app", GetPinnedAppStatus());
2964 
2965   // Removing an item should simply close it and everything should shift.
2966   syncer::SyncChangeList sync_list3;
2967   InsertAddPinChange(&sync_list3, 0, extension_gmail_app_->id());
2968   SendPinChanges(sync_list3, true);
2969   EXPECT_EQ("Chrome, Gmail, *platform_app", GetPinnedAppStatus());
2970 }
2971 
2972 // Each user has a different set of applications pinned. Check that when
2973 // switching between the two users, the state gets properly set.
TEST_F(ChromeLauncherControllerTest,UserSwitchIconRestore)2974 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestore) {
2975   syncer::SyncChangeList user_a;
2976   syncer::SyncChangeList user_b;
2977 
2978   SetUpMultiUserScenario(&user_a, &user_b);
2979 
2980   // Show user 1.
2981   SendPinChanges(user_a, true);
2982   EXPECT_EQ("App1, App2, Gmail, *Platform_App, Doc, App5, Chrome",
2983             GetPinnedAppStatus());
2984 
2985   // Show user 2.
2986   SendPinChanges(user_b, true);
2987   EXPECT_EQ("App6, App7, App8, Chrome", GetPinnedAppStatus());
2988 
2989   // Switch back to 1.
2990   SendPinChanges(user_a, true);
2991   EXPECT_EQ("App1, App2, Gmail, *Platform_App, Doc, App5, Chrome",
2992             GetPinnedAppStatus());
2993 
2994   // Switch back to 2.
2995   SendPinChanges(user_b, true);
2996   EXPECT_EQ("App6, App7, App8, Chrome", GetPinnedAppStatus());
2997 }
2998 
2999 // Each user has a different set of applications pinned, and one user has an
3000 // application running. Check that when switching between the two users, the
3001 // state gets properly set.
TEST_F(ChromeLauncherControllerTest,UserSwitchIconRestoreWithRunningV2App)3002 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestoreWithRunningV2App) {
3003   syncer::SyncChangeList user_a;
3004   syncer::SyncChangeList user_b;
3005 
3006   SetUpMultiUserScenario(&user_a, &user_b);
3007 
3008   // Run the platform (V2) app.
3009   CreateRunningV2App(extension_platform_app_->id());
3010 
3011   // Show user 1.
3012   SendPinChanges(user_a, true);
3013   EXPECT_EQ("App1, App2, Gmail, *Platform_App, Doc, App5, Chrome",
3014             GetPinnedAppStatus());
3015 
3016   // Show user 2.
3017   SendPinChanges(user_b, true);
3018   EXPECT_EQ("App6, App7, App8, Chrome, *platform_app", GetPinnedAppStatus());
3019 
3020   // Switch back to 1.
3021   SendPinChanges(user_a, true);
3022   EXPECT_EQ("App1, App2, Gmail, *Platform_App, Doc, App5, Chrome",
3023             GetPinnedAppStatus());
3024 
3025   // Switch back to 2.
3026   SendPinChanges(user_b, true);
3027   EXPECT_EQ("App6, App7, App8, Chrome, *platform_app", GetPinnedAppStatus());
3028 }
3029 
3030 // Each user has a different set of applications pinned, and one user has an
3031 // application running. The chrome icon is not the last item in the list.
3032 // Check that when switching between the two users, the state gets properly set.
3033 // There was once a bug associated with this.
TEST_F(ChromeLauncherControllerTest,UserSwitchIconRestoreWithRunningV2AppChromeInMiddle)3034 TEST_F(ChromeLauncherControllerTest,
3035        UserSwitchIconRestoreWithRunningV2AppChromeInMiddle) {
3036   syncer::SyncChangeList user_a;
3037   syncer::SyncChangeList user_b;
3038   SetUpMultiUserScenario(&user_a, &user_b);
3039 
3040   // Run the platform (V2) app.
3041   CreateRunningV2App(extension_platform_app_->id());
3042 
3043   // Show user 1.
3044   SendPinChanges(user_a, true);
3045   SetShelfChromeIconIndex(5);
3046   EXPECT_EQ("App1, App2, Gmail, *Platform_App, Doc, Chrome, App5",
3047             GetPinnedAppStatus());
3048 
3049   // Show user 2.
3050   SendPinChanges(user_b, true);
3051   SetShelfChromeIconIndex(3);
3052   EXPECT_EQ("App6, App7, App8, Chrome, *platform_app", GetPinnedAppStatus());
3053 
3054   // Switch back to 1.
3055   SendPinChanges(user_a, true);
3056   SetShelfChromeIconIndex(5);
3057   EXPECT_EQ("App1, App2, Gmail, *Platform_App, Doc, Chrome, App5",
3058             GetPinnedAppStatus());
3059 }
3060 
TEST_F(ChromeLauncherControllerTest,Policy)3061 TEST_F(ChromeLauncherControllerTest, Policy) {
3062   extension_service_->AddExtension(extension2_.get());
3063   extension_service_->AddExtension(extension_gmail_app_.get());
3064 
3065   // Pin policy should be initilized before controller start.
3066   base::ListValue policy_value;
3067   AppendPrefValue(&policy_value, extension1_->id());
3068   AppendPrefValue(&policy_value, extension2_->id());
3069   profile()->GetTestingPrefService()->SetManagedPref(
3070       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
3071 
3072   InitLauncherController();
3073 
3074   // Only |extension2_| should get pinned. |extension1_| is specified but not
3075   // installed, and |extension_gmail_app_| is part of the default set, but that
3076   // shouldn't take effect when the policy override is in place.
3077   EXPECT_EQ("Chrome, App2", GetPinnedAppStatus());
3078 
3079   // Installing |extension1_| should add it to the launcher. Note, App1 goes
3080   // before App2 that is aligned with the pin order in policy.
3081   AddExtension(extension1_.get());
3082   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
3083 
3084   // Removing |extension1_| from the policy should not be reflected in the
3085   // launcher and pin will exist.
3086   policy_value.Remove(0, nullptr);
3087   profile()->GetTestingPrefService()->SetManagedPref(
3088       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
3089   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
3090 }
3091 
TEST_F(ChromeLauncherControllerTest,UnpinWithUninstall)3092 TEST_F(ChromeLauncherControllerTest, UnpinWithUninstall) {
3093   extension_service_->AddExtension(extension_gmail_app_.get());
3094   extension_service_->AddExtension(extension_doc_app_.get());
3095 
3096   InitLauncherController();
3097   StartPrefSyncService(syncer::SyncDataList());
3098 
3099   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3100   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_doc_app_->id()));
3101 
3102   UnloadExtension(extension_gmail_app_->id(),
3103                   UnloadedExtensionReason::UNINSTALL);
3104 
3105   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3106   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_doc_app_->id()));
3107 }
3108 
TEST_F(ChromeLauncherControllerTest,SyncUpdates)3109 TEST_F(ChromeLauncherControllerTest, SyncUpdates) {
3110   extension_service_->AddExtension(extension2_.get());
3111   extension_service_->AddExtension(extension_gmail_app_.get());
3112   extension_service_->AddExtension(extension_doc_app_.get());
3113 
3114   InitLauncherController();
3115 
3116   syncer::SyncChangeList sync_list;
3117   InsertAddPinChange(&sync_list, 10, extension_misc::kChromeAppId);
3118   SendPinChanges(sync_list, true);
3119 
3120   std::vector<std::string> expected_pinned_apps;
3121   std::vector<std::string> actual_pinned_apps;
3122   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3123   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3124 
3125   // Unavailable extensions don't create launcher items.
3126   sync_list.clear();
3127   InsertAddPinChange(&sync_list, 0, extension1_->id());
3128   InsertAddPinChange(&sync_list, 1, extension2_->id());
3129   InsertAddPinChange(&sync_list, 3, extension_doc_app_->id());
3130   SendPinChanges(sync_list, false);
3131 
3132   expected_pinned_apps.push_back(extension2_->id());
3133   expected_pinned_apps.push_back(extension_doc_app_->id());
3134   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3135   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3136 
3137   sync_list.clear();
3138   InsertAddPinChange(&sync_list, 2, extension_gmail_app_->id());
3139   SendPinChanges(sync_list, false);
3140   expected_pinned_apps.insert(expected_pinned_apps.begin() + 1,
3141                               extension_gmail_app_->id());
3142   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3143   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3144 
3145   sync_list.clear();
3146   InsertUpdatePinChange(&sync_list, 0, extension_doc_app_->id());
3147   InsertUpdatePinChange(&sync_list, 1, extension_gmail_app_->id());
3148   InsertUpdatePinChange(&sync_list, 2, extension2_->id());
3149   SendPinChanges(sync_list, false);
3150   std::reverse(expected_pinned_apps.begin(), expected_pinned_apps.end());
3151   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3152   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3153 
3154   // Sending legacy sync change without pin info should not affect pin model.
3155   sync_list.clear();
3156   InsertLegacyPinChange(&sync_list, extension_doc_app_->id());
3157   SendPinChanges(sync_list, false);
3158   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3159   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3160 
3161   sync_list.clear();
3162   InsertRemovePinChange(&sync_list, extension_doc_app_->id());
3163   SendPinChanges(sync_list, false);
3164   expected_pinned_apps.erase(expected_pinned_apps.begin());
3165   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3166   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3167 
3168   sync_list.clear();
3169   InsertRemovePinChange(&sync_list, extension_gmail_app_->id());
3170   InsertRemovePinChange(&sync_list, extension2_->id());
3171   SendPinChanges(sync_list, false);
3172   expected_pinned_apps.clear();
3173   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3174   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3175 }
3176 
TEST_F(ChromeLauncherControllerTest,PendingInsertionOrder)3177 TEST_F(ChromeLauncherControllerTest, PendingInsertionOrder) {
3178   extension_service_->AddExtension(extension1_.get());
3179   extension_service_->AddExtension(extension_gmail_app_.get());
3180 
3181   InitLauncherController();
3182 
3183   syncer::SyncChangeList sync_list;
3184   InsertAddPinChange(&sync_list, 0, extension1_->id());
3185   InsertAddPinChange(&sync_list, 1, extension2_->id());
3186   InsertAddPinChange(&sync_list, 2, extension_gmail_app_->id());
3187   SendPinChanges(sync_list, true);
3188 
3189   std::vector<std::string> expected_pinned_apps;
3190   expected_pinned_apps.push_back(extension1_->id());
3191   expected_pinned_apps.push_back(extension_gmail_app_->id());
3192   std::vector<std::string> actual_pinned_apps;
3193 
3194   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3195   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3196 
3197   // Install |extension2| and verify it shows up between the other two.
3198   AddExtension(extension2_.get());
3199   expected_pinned_apps.insert(expected_pinned_apps.begin() + 1,
3200                               extension2_->id());
3201   GetPinnedAppIds(launcher_controller_.get(), &actual_pinned_apps);
3202   EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
3203 }
3204 
3205 // Ensure |controller| creates the expected menu items for the given shelf item.
CheckAppMenu(ChromeLauncherController * controller,const ash::ShelfItem & item,size_t expected_item_count,base::string16 expected_item_titles[])3206 void CheckAppMenu(ChromeLauncherController* controller,
3207                   const ash::ShelfItem& item,
3208                   size_t expected_item_count,
3209                   base::string16 expected_item_titles[]) {
3210   auto items = controller->GetAppMenuItemsForTesting(item);
3211   ASSERT_EQ(expected_item_count, items.size());
3212   for (size_t i = 0; i < expected_item_count; i++)
3213     EXPECT_EQ(expected_item_titles[i], items[i].title);
3214 }
3215 
3216 // Check that browsers get reflected correctly in the launcher menu.
TEST_F(ChromeLauncherControllerTest,BrowserMenuGeneration)3217 TEST_F(ChromeLauncherControllerTest, BrowserMenuGeneration) {
3218   EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
3219   chrome::NewTab(browser());
3220 
3221   InitLauncherController();
3222 
3223   // Check that the browser list is empty at this time.
3224   ash::ShelfItem item_browser;
3225   item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
3226   item_browser.id = ash::ShelfID(extension_misc::kChromeAppId);
3227   CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr);
3228 
3229   // Now make the created browser() visible by showing its browser window.
3230   browser()->window()->Show();
3231   base::string16 title1 = ASCIIToUTF16("Test1");
3232   NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
3233   base::string16 one_menu_item[] = {title1};
3234 
3235   CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item);
3236 
3237   // Create one more browser/window and check that one more was added.
3238   std::unique_ptr<Browser> browser2(
3239       CreateBrowserWithTestWindowForProfile(profile()));
3240   chrome::NewTab(browser2.get());
3241   browser2->window()->Show();
3242   base::string16 title2 = ASCIIToUTF16("Test2");
3243   NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
3244                                       title2);
3245 
3246   // Check that the list contains now two entries - make furthermore sure that
3247   // the active item is the first entry.
3248   base::string16 two_menu_items[] = {title1, title2};
3249   CheckAppMenu(launcher_controller_.get(), item_browser, 2, two_menu_items);
3250 
3251   // Apparently we have to close all tabs we have.
3252   chrome::CloseTab(browser2.get());
3253 }
3254 
3255 // Check the multi profile case where only user related browsers should show up.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,BrowserMenuGenerationTwoUsers)3256 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3257        BrowserMenuGenerationTwoUsers) {
3258   // Create a browser item in the LauncherController.
3259   InitLauncherController();
3260 
3261   ash::ShelfItem item_browser;
3262   item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
3263   item_browser.id = ash::ShelfID(extension_misc::kChromeAppId);
3264 
3265   // Check that the menu is empty.
3266   chrome::NewTab(browser());
3267   CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr);
3268 
3269   // Show the created |browser()| by showing its window.
3270   browser()->window()->Show();
3271   base::string16 title1 = ASCIIToUTF16("Test1");
3272   NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
3273   base::string16 one_menu_item1[] = {title1};
3274   CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item1);
3275 
3276   // Create a browser for another user and check that it is not included in the
3277   // users running browser list.
3278   std::string user2 = "user2";
3279   TestingProfile* profile2 = CreateMultiUserProfile(user2);
3280   const AccountId account_id2(
3281       multi_user_util::GetAccountIdFromProfile(profile2));
3282   std::unique_ptr<Browser> browser2(
3283       CreateBrowserAndTabWithProfile(profile2, user2, "http://test2"));
3284   base::string16 one_menu_item2[] = {ASCIIToUTF16(user2)};
3285   CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item1);
3286 
3287   // Switch to the other user and make sure that only that browser window gets
3288   // shown.
3289   SwitchActiveUser(account_id2);
3290   CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item2);
3291 
3292   // Transferred browsers of other users should not show up in the list.
3293   MultiUserWindowManagerHelper::GetWindowManager()->ShowWindowForUser(
3294       browser()->window()->GetNativeWindow(), account_id2);
3295   CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item2);
3296 
3297   chrome::CloseTab(browser2.get());
3298 }
3299 
3300 // Check that V1 apps are correctly reflected in the launcher menu using the
3301 // refocus logic.
3302 // Note that the extension matching logic is tested by the extension system
3303 // and does not need a separate test here.
TEST_F(ChromeLauncherControllerTest,V1AppMenuGeneration)3304 TEST_F(ChromeLauncherControllerTest, V1AppMenuGeneration) {
3305   EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
3306   EXPECT_EQ(0, browser()->tab_strip_model()->count());
3307 
3308   InitLauncherControllerWithBrowser();
3309   StartPrefSyncService(syncer::SyncDataList());
3310 
3311   // The model should only contain the browser shortcut item.
3312   EXPECT_EQ(1, model_->item_count());
3313   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3314 
3315   // Installing |extension_gmail_app_| pins it to the launcher.
3316   const ash::ShelfID gmail_id(extension_gmail_app_->id());
3317   AddExtension(extension_gmail_app_.get());
3318   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3319   launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(kGmailUrl));
3320 
3321   // Check the menu content.
3322   ash::ShelfItem item_browser;
3323   item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
3324   item_browser.id = ash::ShelfID(extension_misc::kChromeAppId);
3325 
3326   ash::ShelfItem item_gmail;
3327   item_gmail.type = ash::TYPE_PINNED_APP;
3328   item_gmail.id = gmail_id;
3329   CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr);
3330 
3331   // Set the gmail URL to a new tab.
3332   base::string16 title1 = ASCIIToUTF16("Test1");
3333   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title1);
3334 
3335   base::string16 one_menu_item[] = {title1};
3336   CheckAppMenu(launcher_controller_.get(), item_gmail, 1, one_menu_item);
3337 
3338   // Create one empty tab.
3339   chrome::NewTab(browser());
3340   base::string16 title2 = ASCIIToUTF16("Test2");
3341   NavigateAndCommitActiveTabWithTitle(browser(), GURL("https://bla"), title2);
3342 
3343   // and another one with another gmail instance.
3344   chrome::NewTab(browser());
3345   base::string16 title3 = ASCIIToUTF16("Test3");
3346   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title3);
3347   base::string16 two_menu_items[] = {title1, title3};
3348   CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items);
3349 
3350   // Even though the item is in the V1 app list, it should also be in the
3351   // browser list.
3352   base::string16 browser_menu_item[] = {title3};
3353   CheckAppMenu(launcher_controller_.get(), item_browser, 1, browser_menu_item);
3354 
3355   // Test that closing of (all) the item(s) does work (and all menus get
3356   // updated properly).
3357   launcher_controller_->Close(item_gmail.id);
3358 
3359   CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr);
3360   base::string16 browser_menu_item2[] = {title2};
3361   CheckAppMenu(launcher_controller_.get(), item_browser, 1, browser_menu_item2);
3362 }
3363 
3364 // Check the multi profile case where only user related apps should show up.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V1AppMenuGenerationTwoUsers)3365 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3366        V1AppMenuGenerationTwoUsers) {
3367   // Create a browser item in the LauncherController.
3368   InitLauncherController();
3369   StartPrefSyncService(syncer::SyncDataList());
3370   chrome::NewTab(browser());
3371 
3372   // Installing |extension_gmail_app_| pins it to the launcher.
3373   const ash::ShelfID gmail_id(extension_gmail_app_->id());
3374   AddExtension(extension_gmail_app_.get());
3375   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3376   launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(kGmailUrl));
3377 
3378   // Check the menu content.
3379   ash::ShelfItem item_browser;
3380   item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
3381   item_browser.id = ash::ShelfID(extension_misc::kChromeAppId);
3382 
3383   ash::ShelfItem item_gmail;
3384   item_gmail.type = ash::TYPE_PINNED_APP;
3385   item_gmail.id = gmail_id;
3386   CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr);
3387 
3388   // Set the gmail URL to a new tab.
3389   base::string16 title1 = ASCIIToUTF16("Test1");
3390   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title1);
3391 
3392   base::string16 one_menu_item[] = {title1};
3393   CheckAppMenu(launcher_controller_.get(), item_gmail, 1, one_menu_item);
3394 
3395   // Create a second profile and switch to that user.
3396   std::string user2 = "user2";
3397   TestingProfile* profile2 = CreateMultiUserProfile(user2);
3398   const AccountId account_id2(
3399       multi_user_util::GetAccountIdFromProfile(profile2));
3400   SwitchActiveUser(account_id2);
3401 
3402   // No item should have content yet.
3403   CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr);
3404   CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr);
3405 
3406   // Transfer the browser of the first user - it should still not show up.
3407   MultiUserWindowManagerHelper::GetWindowManager()->ShowWindowForUser(
3408       browser()->window()->GetNativeWindow(), account_id2);
3409 
3410   CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr);
3411   CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr);
3412 }
3413 
3414 // Check that V2 applications are creating items properly in the launcher when
3415 // instantiated by the current user.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V2AppHandlingTwoUsers)3416 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3417        V2AppHandlingTwoUsers) {
3418   InitLauncherController();
3419   const AccountId account_id(
3420       multi_user_util::GetAccountIdFromProfile(profile()));
3421   // Check that there is a browser.
3422   EXPECT_EQ(1, model_->item_count());
3423 
3424   // Add a v2 app.
3425   AddExtension(extension1_.get());
3426   V2App v2_app(profile(), extension1_.get());
3427   EXPECT_EQ(2, model_->item_count());
3428 
3429   // Create a profile for our second user (will be destroyed by the framework).
3430   TestingProfile* profile2 = CreateMultiUserProfile("user2");
3431   const AccountId account_id2(
3432       multi_user_util::GetAccountIdFromProfile(profile2));
3433 
3434   // After switching users the item should go away.
3435   SwitchActiveUser(account_id2);
3436   EXPECT_EQ(1, model_->item_count());
3437 
3438   // And it should come back when switching back.
3439   SwitchActiveUser(account_id);
3440   EXPECT_EQ(2, model_->item_count());
3441 }
3442 
3443 // Check that V2 applications are creating items properly in edge cases:
3444 // a background user creates a V2 app, gets active and inactive again and then
3445 // deletes the app.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V2AppHandlingTwoUsersEdgeCases)3446 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3447        V2AppHandlingTwoUsersEdgeCases) {
3448   InitLauncherController();
3449   // Create a profile for our second user (will be destroyed by the framework).
3450   TestingProfile* profile2 = CreateMultiUserProfile("user2");
3451   const AccountId account_id(
3452       multi_user_util::GetAccountIdFromProfile(profile()));
3453   const AccountId account_id2(
3454       multi_user_util::GetAccountIdFromProfile(profile2));
3455   // Check that there is a browser, back button and a app launcher.
3456   EXPECT_EQ(1, model_->item_count());
3457 
3458   // Switch to an inactive user.
3459   SwitchActiveUser(account_id2);
3460   EXPECT_EQ(1, model_->item_count());
3461 
3462   // Add the v2 app to the inactive user and check that no item was added to
3463   // the launcher.
3464   {
3465     AddExtension(extension1_.get());
3466     V2App v2_app(profile(), extension1_.get());
3467     EXPECT_EQ(1, model_->item_count());
3468 
3469     // Switch to the primary user and check that the item is shown.
3470     SwitchActiveUser(account_id);
3471     EXPECT_EQ(2, model_->item_count());
3472 
3473     // Switch to the second user and check that the item goes away - even if the
3474     // item gets closed.
3475     SwitchActiveUser(account_id2);
3476     EXPECT_EQ(1, model_->item_count());
3477   }
3478 
3479   app_service_test().WaitForAppService();
3480   // After the application was killed there should still be 1 item.
3481   EXPECT_EQ(1, model_->item_count());
3482 
3483   // Switching then back to the default user should not show the additional item
3484   // anymore.
3485   SwitchActiveUser(account_id);
3486   EXPECT_EQ(1, model_->item_count());
3487 }
3488 
TEST_F(ChromeLauncherControllerTest,Active)3489 TEST_F(ChromeLauncherControllerTest, Active) {
3490   InitLauncherController();
3491 
3492   // Creates a new app window.
3493   int initial_item_count = model_->item_count();
3494   AddExtension(extension1_.get());
3495   V2App app_1(profile(), extension1_.get());
3496   EXPECT_TRUE(app_1.window()->GetNativeWindow()->IsVisible());
3497   EXPECT_EQ(initial_item_count + 1, model_->item_count());
3498   ash::ShelfItemDelegate* app_item_delegate_1 =
3499       model_->GetShelfItemDelegate(model_->items()[initial_item_count].id);
3500   ASSERT_TRUE(app_item_delegate_1);
3501   AppWindowLauncherItemController* app_item_controller_1 =
3502       app_item_delegate_1->AsAppWindowLauncherItemController();
3503   ASSERT_TRUE(app_item_controller_1);
3504   ui::BaseWindow* last_active =
3505       GetLastActiveWindowForItemController(app_item_controller_1);
3506   EXPECT_EQ(app_1.window()->GetNativeWindow(), last_active->GetNativeWindow());
3507   // Change the status so that we can verify it gets reset when the active
3508   // window changes.
3509   launcher_controller_->SetItemStatus(app_item_delegate_1->shelf_id(),
3510                                       ash::STATUS_ATTENTION);
3511 
3512   // Creates another app window, which should become active and reset |app_1|'s
3513   // status (to running).
3514   AddExtension(extension2_.get());
3515   V2App app_2(profile(), extension2_.get());
3516   EXPECT_TRUE(app_2.window()->GetNativeWindow()->IsVisible());
3517   EXPECT_EQ(initial_item_count + 2, model_->item_count());
3518   ash::ShelfItemDelegate* app_item_delegate_2 =
3519       model_->GetShelfItemDelegate(model_->items()[initial_item_count + 1].id);
3520   ASSERT_TRUE(app_item_delegate_2);
3521   AppWindowLauncherItemController* app_item_controller_2 =
3522       app_item_delegate_2->AsAppWindowLauncherItemController();
3523   ASSERT_TRUE(app_item_controller_2);
3524   last_active = GetLastActiveWindowForItemController(app_item_controller_2);
3525   EXPECT_EQ(app_2.window()->GetNativeWindow(), last_active->GetNativeWindow());
3526   const ash::ShelfItem* shelf_item_1 =
3527       launcher_controller_->GetItem(app_item_delegate_1->shelf_id());
3528   ASSERT_TRUE(shelf_item_1);
3529   EXPECT_EQ(ash::STATUS_RUNNING, shelf_item_1->status);
3530 
3531   launcher_controller_->SetItemStatus(app_item_delegate_2->shelf_id(),
3532                                       ash::STATUS_ATTENTION);
3533 
3534   // Activate the first window, which should reset the status of the
3535   // second apps window.
3536   app_1.window()->GetBaseWindow()->Activate();
3537   const ash::ShelfItem* shelf_item_2 =
3538       launcher_controller_->GetItem(app_item_delegate_2->shelf_id());
3539   ASSERT_TRUE(shelf_item_2);
3540   EXPECT_EQ(ash::STATUS_RUNNING, shelf_item_2->status);
3541 }
3542 
3543 // Check that V2 applications will be made visible on the target desktop if
3544 // another window of the same type got previously teleported there.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V2AppFollowsTeleportedWindow)3545 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3546        V2AppFollowsTeleportedWindow) {
3547   InitLauncherController();
3548   ash::MultiUserWindowManager* window_manager =
3549       MultiUserWindowManagerHelper::GetWindowManager();
3550 
3551   // Create and add three users / profiles, and go to #1's desktop.
3552   TestingProfile* profile1 = CreateMultiUserProfile("user-1");
3553   TestingProfile* profile2 = CreateMultiUserProfile("user-2");
3554   TestingProfile* profile3 = CreateMultiUserProfile("user-3");
3555   const AccountId account_id1(
3556       multi_user_util::GetAccountIdFromProfile(profile1));
3557   const AccountId account_id2(
3558       multi_user_util::GetAccountIdFromProfile(profile2));
3559   const AccountId account_id3(
3560       multi_user_util::GetAccountIdFromProfile(profile3));
3561 
3562   extensions::TestExtensionSystem* extension_system1(
3563       static_cast<extensions::TestExtensionSystem*>(
3564           extensions::ExtensionSystem::Get(profile1)));
3565   extensions::ExtensionService* extension_service1 =
3566       extension_system1->CreateExtensionService(
3567           base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
3568   extension_service1->Init();
3569   apps::AppServiceProxy* proxy1 =
3570       apps::AppServiceProxyFactory::GetForProfile(profile1);
3571 
3572   SwitchActiveUser(account_id1);
3573 
3574   // A v2 app for user #1 should be shown first and get hidden when switching
3575   // to desktop #2.
3576   extension_service1->AddExtension(extension1_.get());
3577   proxy1->FlushMojoCallsForTesting();
3578   V2App v2_app_1(profile1, extension1_.get());
3579   EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3580   SwitchActiveUser(account_id2);
3581   app_service_test().FlushMojoCalls();
3582   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3583 
3584   // Add a v2 app for user #1 while on desktop #2 should not be shown.
3585   V2App v2_app_2(profile1, extension1_.get());
3586   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3587   EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3588 
3589   // Teleport the app from user #1 to the desktop #2 should show it.
3590   window_manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(),
3591                                     account_id2);
3592   EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3593   EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3594 
3595   // Creating a new application for user #1 on desktop #2 should teleport it
3596   // there automatically.
3597   V2App v2_app_3(profile1, extension1_.get());
3598   EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3599   EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3600   EXPECT_TRUE(v2_app_3.window()->GetNativeWindow()->IsVisible());
3601 
3602   // Switching back to desktop#1 and creating an app for user #1 should move
3603   // the app on desktop #1.
3604   SwitchActiveUser(account_id1);
3605   app_service_test().FlushMojoCalls();
3606   V2App v2_app_4(profile1, extension1_.get());
3607   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3608   EXPECT_TRUE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3609   EXPECT_FALSE(v2_app_3.window()->GetNativeWindow()->IsVisible());
3610   EXPECT_TRUE(v2_app_4.window()->GetNativeWindow()->IsVisible());
3611 
3612   // Switching to desktop #3 and creating an app for user #1 should place it
3613   // on that user's desktop (#1).
3614   SwitchActiveUser(account_id3);
3615   app_service_test().FlushMojoCalls();
3616   V2App v2_app_5(profile1, extension1_.get());
3617   EXPECT_FALSE(v2_app_5.window()->GetNativeWindow()->IsVisible());
3618   SwitchActiveUser(account_id1);
3619   EXPECT_TRUE(v2_app_5.window()->GetNativeWindow()->IsVisible());
3620 
3621   // Switching to desktop #2, hiding the app window and creating an app should
3622   // teleport there automatically.
3623   SwitchActiveUser(account_id2);
3624   app_service_test().FlushMojoCalls();
3625   v2_app_1.window()->Hide();
3626   V2App v2_app_6(profile1, extension1_.get());
3627   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3628   EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3629   EXPECT_TRUE(v2_app_6.window()->GetNativeWindow()->IsVisible());
3630 }
3631 
3632 // Check that V2 applications hide correctly on the shelf when the app window
3633 // is hidden.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,V2AppHiddenWindows)3634 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3635        V2AppHiddenWindows) {
3636   InitLauncherController();
3637 
3638   TestingProfile* profile2 = CreateMultiUserProfile("user-2");
3639   const AccountId account_id2(
3640       multi_user_util::GetAccountIdFromProfile(profile2));
3641   // If switch to account_id2 is not run, the following switch to account_id
3642   // is invalid, because the user account is not changed, so switch to
3643   // account_id2 first.
3644   SwitchActiveUser(account_id2);
3645 
3646   const AccountId account_id(
3647       multi_user_util::GetAccountIdFromProfile(profile()));
3648   SwitchActiveUser(account_id);
3649   EXPECT_EQ(1, model_->item_count());
3650 
3651   AddExtension(extension1_.get());
3652   V2App v2_app_1(profile(), extension1_.get());
3653   EXPECT_EQ(2, model_->item_count());
3654   {
3655     // Hide and show the app.
3656     v2_app_1.window()->Hide();
3657     EXPECT_EQ(1, model_->item_count());
3658 
3659     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3660     EXPECT_EQ(2, model_->item_count());
3661   }
3662   {
3663     // Switch user, hide and show the app and switch back.
3664     SwitchActiveUser(account_id2);
3665     EXPECT_EQ(1, model_->item_count());
3666 
3667     v2_app_1.window()->Hide();
3668     EXPECT_EQ(1, model_->item_count());
3669 
3670     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3671     EXPECT_EQ(1, model_->item_count());
3672 
3673     SwitchActiveUser(account_id);
3674     EXPECT_EQ(2, model_->item_count());
3675   }
3676   {
3677     // Switch user, hide the app, switch back and then show it again.
3678     SwitchActiveUser(account_id2);
3679     EXPECT_EQ(1, model_->item_count());
3680 
3681     v2_app_1.window()->Hide();
3682     EXPECT_EQ(1, model_->item_count());
3683 
3684     SwitchActiveUser(account_id);
3685     // The following expectation does not work in current impl. It was working
3686     // before because MultiProfileSupport is not attached to user
3687     // associated with profile() hence not actually handling windows for the
3688     // user. It is a real bug. See http://crbug.com/693634
3689     // EXPECT_EQ(2, model_->item_count());
3690 
3691     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3692     EXPECT_EQ(2, model_->item_count());
3693   }
3694   {
3695     // Create a second app, hide and show it and then hide both apps.
3696     V2App v2_app_2(profile(), extension1_.get());
3697     EXPECT_EQ(2, model_->item_count());
3698 
3699     v2_app_2.window()->Hide();
3700     EXPECT_EQ(2, model_->item_count());
3701 
3702     v2_app_2.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3703     EXPECT_EQ(2, model_->item_count());
3704 
3705     v2_app_1.window()->Hide();
3706     v2_app_2.window()->Hide();
3707     EXPECT_EQ(1, model_->item_count());
3708   }
3709 }
3710 
3711 // Checks that spinners are hidden and restored on profile switching
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,SpinnersUpdateOnUserSwitch)3712 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3713        SpinnersUpdateOnUserSwitch) {
3714   InitLauncherController();
3715 
3716   const AccountId account_id(
3717       multi_user_util::GetAccountIdFromProfile(profile()));
3718   const std::string user2 = "user2";
3719   const TestingProfile* profile2 = CreateMultiUserProfile(user2);
3720   const AccountId account_id2(
3721       multi_user_util::GetAccountIdFromProfile(profile2));
3722 
3723   const std::string app_id = extension1_->id();
3724   extension_service_->AddExtension(extension1_.get());
3725 
3726   EXPECT_EQ(1, model_->item_count());
3727   EXPECT_FALSE(
3728       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3729 
3730   // Add a spinner to the shelf
3731   launcher_controller_->GetShelfSpinnerController()->AddSpinnerToShelf(
3732       app_id, std::make_unique<ShelfSpinnerItemController>(app_id));
3733   EXPECT_EQ(2, model_->item_count());
3734   EXPECT_TRUE(
3735       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3736 
3737   // Switch to a new profile
3738   SwitchActiveUser(account_id2);
3739   EXPECT_EQ(1, model_->item_count());
3740   EXPECT_FALSE(
3741       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3742 
3743   // Switch back
3744   SwitchActiveUser(account_id);
3745   EXPECT_EQ(2, model_->item_count());
3746   EXPECT_TRUE(
3747       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3748 
3749   // Close the spinner
3750   launcher_controller_->GetShelfSpinnerController()->CloseSpinner(app_id);
3751   EXPECT_EQ(1, model_->item_count());
3752   EXPECT_FALSE(
3753       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3754 }
3755 
3756 // Checks that pinned spinners are hidden and restored on profile switching
3757 // but are not removed when the spinner closes.
TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,PinnedSpinnersUpdateOnUserSwitch)3758 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
3759        PinnedSpinnersUpdateOnUserSwitch) {
3760   InitLauncherController();
3761 
3762   const AccountId account_id(
3763       multi_user_util::GetAccountIdFromProfile(profile()));
3764   const std::string user2 = "user2";
3765   const TestingProfile* profile2 = CreateMultiUserProfile(user2);
3766   const AccountId account_id2(
3767       multi_user_util::GetAccountIdFromProfile(profile2));
3768 
3769   const std::string app_id = extension1_->id();
3770   AddExtension(extension1_.get());
3771 
3772   EXPECT_EQ(1, model_->item_count());
3773   EXPECT_FALSE(
3774       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3775 
3776   // Pin an app to the shelf
3777   launcher_controller_->PinAppWithID(app_id);
3778   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
3779   EXPECT_EQ(2, model_->item_count());
3780   EXPECT_FALSE(
3781       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3782 
3783   // Activate the spinner
3784   launcher_controller_->GetShelfSpinnerController()->AddSpinnerToShelf(
3785       app_id, std::make_unique<ShelfSpinnerItemController>(app_id));
3786   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
3787   EXPECT_EQ(2, model_->item_count());
3788   EXPECT_TRUE(
3789       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3790 
3791   // Switch to a new profile
3792   SwitchActiveUser(account_id2);
3793   app_service_test().FlushMojoCalls();
3794   EXPECT_FALSE(launcher_controller_->IsAppPinned(app_id));
3795   EXPECT_EQ(1, model_->item_count());
3796   EXPECT_FALSE(
3797       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3798 
3799   // Switch back
3800   SwitchActiveUser(account_id);
3801   app_service_test().FlushMojoCalls();
3802   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
3803   EXPECT_EQ(2, model_->item_count());
3804   EXPECT_TRUE(
3805       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3806 
3807   // Close the spinner
3808   launcher_controller_->GetShelfSpinnerController()->CloseSpinner(app_id);
3809   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
3810   EXPECT_EQ(2, model_->item_count());
3811   EXPECT_FALSE(
3812       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
3813 }
3814 
3815 // Checks that the generated menu list properly activates items.
TEST_F(ChromeLauncherControllerTest,V1AppMenuExecution)3816 TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) {
3817   InitLauncherControllerWithBrowser();
3818   StartPrefSyncService(syncer::SyncDataList());
3819 
3820   // Add |extension_gmail_app_| to the launcher and add two items.
3821   GURL gmail = GURL("https://mail.google.com/mail/u");
3822   const ash::ShelfID gmail_id(extension_gmail_app_->id());
3823   AddExtension(extension_gmail_app_.get());
3824   launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(kGmailUrl));
3825   base::string16 title1 = ASCIIToUTF16("Test1");
3826   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title1);
3827   chrome::NewTab(browser());
3828   base::string16 title2 = ASCIIToUTF16("Test2");
3829   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title2);
3830   app_service_test().WaitForAppService();
3831 
3832   // Check that the menu is properly set.
3833   ash::ShelfItem item_gmail;
3834   item_gmail.type = ash::TYPE_PINNED_APP;
3835   item_gmail.id = gmail_id;
3836   base::string16 two_menu_items[] = {title1, title2};
3837   CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items);
3838   ash::ShelfItemDelegate* item_delegate =
3839       model_->GetShelfItemDelegate(gmail_id);
3840   ASSERT_TRUE(item_delegate);
3841   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
3842   // Execute the second item in the menu, after the title,
3843   // this shouldn't do anything since that item is already the active tab.
3844   {
3845     ash::ShelfApplicationMenuModel menu(
3846         base::string16(),
3847         launcher_controller_->GetAppMenuItemsForTesting(item_gmail),
3848         item_delegate);
3849     menu.ActivatedAt(2);
3850   }
3851   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
3852 
3853   // Execute the first item in the menu, after the title,
3854   // this should activate the other tab.
3855   {
3856     ash::ShelfApplicationMenuModel menu(
3857         base::string16(),
3858         launcher_controller_->GetAppMenuItemsForTesting(item_gmail),
3859         item_delegate);
3860     menu.ActivatedAt(1);
3861   }
3862   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
3863 }
3864 
3865 // Checks that the generated menu list properly deletes items.
TEST_F(ChromeLauncherControllerTest,V1AppMenuDeletionExecution)3866 TEST_F(ChromeLauncherControllerTest, V1AppMenuDeletionExecution) {
3867   InitLauncherControllerWithBrowser();
3868   StartPrefSyncService(syncer::SyncDataList());
3869 
3870   // Add |extension_gmail_app_| to the launcher and add two items.
3871   const ash::ShelfID gmail_id(extension_gmail_app_->id());
3872   AddExtension(extension_gmail_app_.get());
3873   launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(kGmailUrl));
3874   base::string16 title1 = ASCIIToUTF16("Test1");
3875   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title1);
3876   chrome::NewTab(browser());
3877   base::string16 title2 = ASCIIToUTF16("Test2");
3878   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title2);
3879   app_service_test().WaitForAppService();
3880 
3881   // Check that the menu is properly set.
3882   ash::ShelfItem item_gmail;
3883   item_gmail.type = ash::TYPE_PINNED_APP;
3884   item_gmail.id = gmail_id;
3885   base::string16 two_menu_items[] = {title1, title2};
3886   CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items);
3887 
3888   ash::ShelfItemDelegate* item_delegate =
3889       model_->GetShelfItemDelegate(gmail_id);
3890   ASSERT_TRUE(item_delegate);
3891   int tabs = browser()->tab_strip_model()->count();
3892   // Activate the proper tab through the menu item.
3893   {
3894     auto items = launcher_controller_->GetAppMenuItemsForTesting(item_gmail);
3895     item_delegate->ExecuteCommand(false, 1, ui::EF_NONE,
3896                                   display::kInvalidDisplayId);
3897     EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
3898   }
3899 
3900   // Delete one tab through the menu item.
3901   {
3902     auto items = launcher_controller_->GetAppMenuItemsForTesting(item_gmail);
3903     item_delegate->ExecuteCommand(false, 1, ui::EF_SHIFT_DOWN,
3904                                   display::kInvalidDisplayId);
3905     EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
3906   }
3907 }
3908 
3909 // Tests that the Gmail extension matches more than the app itself claims with
3910 // the manifest file.
TEST_F(ChromeLauncherControllerTest,GmailMatching)3911 TEST_F(ChromeLauncherControllerTest, GmailMatching) {
3912   InitLauncherControllerWithBrowser();
3913   StartPrefSyncService(syncer::SyncDataList());
3914 
3915   // Create a Gmail browser tab.
3916   chrome::NewTab(browser());
3917   base::string16 title = ASCIIToUTF16("Test");
3918   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kGmailUrl), title);
3919   content::WebContents* content =
3920       browser()->tab_strip_model()->GetActiveWebContents();
3921 
3922   // Check that the launcher controller does not recognize the running app.
3923   EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
3924 
3925   // Installing |extension_gmail_app_| pins it to the launcher.
3926   const ash::ShelfID gmail_id(extension_gmail_app_->id());
3927   AddExtension(extension_gmail_app_.get());
3928   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3929 
3930   // Check that it is now handled.
3931   EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
3932 
3933   // Check also that the app has detected that properly.
3934   ash::ShelfItem item_gmail;
3935   item_gmail.type = ash::TYPE_PINNED_APP;
3936   item_gmail.id = gmail_id;
3937   EXPECT_EQ(1U,
3938             launcher_controller_->GetAppMenuItemsForTesting(item_gmail).size());
3939 }
3940 
3941 // Tests that the Gmail extension does not match the offline version.
TEST_F(ChromeLauncherControllerTest,GmailOfflineMatching)3942 TEST_F(ChromeLauncherControllerTest, GmailOfflineMatching) {
3943   InitLauncherControllerWithBrowser();
3944 
3945   StartPrefSyncService(syncer::SyncDataList());
3946 
3947   // Create a Gmail browser tab.
3948   chrome::NewTab(browser());
3949   base::string16 title = ASCIIToUTF16("Test");
3950   NavigateAndCommitActiveTabWithTitle(browser(), GURL(kOfflineGmailUrl), title);
3951   content::WebContents* content =
3952       browser()->tab_strip_model()->GetActiveWebContents();
3953 
3954   // Installing |extension_gmail_app_| pins it to the launcher.
3955   const ash::ShelfID gmail_id(extension_gmail_app_->id());
3956   AddExtension(extension_gmail_app_.get());
3957   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension_gmail_app_->id()));
3958 
3959   // The content should not be able to be handled by the app.
3960   EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
3961 }
3962 
3963 // Verify that the launcher item positions are persisted and restored.
TEST_F(ChromeLauncherControllerTest,PersistLauncherItemPositions)3964 TEST_F(ChromeLauncherControllerTest, PersistLauncherItemPositions) {
3965   InitLauncherController();
3966 
3967   TestLauncherControllerHelper* helper = new TestLauncherControllerHelper;
3968   SetLauncherControllerHelper(helper);
3969 
3970   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[0].type);
3971 
3972   TabStripModel* tab_strip_model = browser()->tab_strip_model();
3973   EXPECT_EQ(0, tab_strip_model->count());
3974   chrome::NewTab(browser());
3975   chrome::NewTab(browser());
3976   EXPECT_EQ(2, tab_strip_model->count());
3977   helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
3978   helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
3979 
3980   EXPECT_FALSE(launcher_controller_->IsAppPinned("1"));
3981   launcher_controller_->PinAppWithID("1");
3982   EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
3983   launcher_controller_->PinAppWithID("2");
3984 
3985   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[0].type);
3986   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
3987   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
3988 
3989   // Move browser shortcut item from index 0 to index 2.
3990   model_->Move(0, 2);
3991   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[0].type);
3992   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
3993   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[2].type);
3994 
3995   RecreateLauncherController();
3996   helper = new TestLauncherControllerHelper(profile());
3997   helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
3998   helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
3999   SetLauncherControllerHelper(helper);
4000   launcher_controller_->Init();
4001 
4002   // Check ShelfItems are restored after resetting ChromeLauncherController.
4003   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[0].type);
4004   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
4005   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[2].type);
4006 }
4007 
4008 // Verifies pinned apps are persisted and restored.
TEST_F(ChromeLauncherControllerTest,PersistPinned)4009 TEST_F(ChromeLauncherControllerTest, PersistPinned) {
4010   InitLauncherControllerWithBrowser();
4011   size_t initial_size = model_->items().size();
4012 
4013   TabStripModel* tab_strip_model = browser()->tab_strip_model();
4014   EXPECT_EQ(1, tab_strip_model->count());
4015 
4016   TestLauncherControllerHelper* helper = new TestLauncherControllerHelper;
4017   helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
4018   SetLauncherControllerHelper(helper);
4019 
4020   // app_icon_loader is owned by ChromeLauncherController.
4021   TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl;
4022   app_icon_loader->AddSupportedApp("1");
4023   SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader));
4024   EXPECT_EQ(0, app_icon_loader->fetch_count());
4025 
4026   launcher_controller_->PinAppWithID("1");
4027   const int app_index = model_->ItemIndexByID(ash::ShelfID("1"));
4028   EXPECT_EQ(1, app_icon_loader->fetch_count());
4029   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[app_index].type);
4030   EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
4031   EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
4032   EXPECT_EQ(initial_size + 1, model_->items().size());
4033 
4034   RecreateLauncherController();
4035   helper = new TestLauncherControllerHelper(profile());
4036   helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
4037   SetLauncherControllerHelper(helper);
4038   // app_icon_loader is owned by ChromeLauncherController.
4039   app_icon_loader = new TestAppIconLoaderImpl;
4040   app_icon_loader->AddSupportedApp("1");
4041   SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader));
4042   launcher_controller_->Init();
4043 
4044   EXPECT_EQ(1, app_icon_loader->fetch_count());
4045   ASSERT_EQ(initial_size + 1, model_->items().size());
4046   EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
4047   EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
4048   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[app_index].type);
4049 
4050   launcher_controller_->UnpinAppWithID("1");
4051   EXPECT_EQ(initial_size + 1, model_->items().size());
4052 
4053   tab_strip_model->CloseWebContentsAt(0, 0);
4054   EXPECT_EQ(initial_size, model_->items().size());
4055 }
4056 
4057 // Verifies that ShelfID property is updated for browsers that are present when
4058 // ChromeLauncherController is created.
TEST_F(ChromeLauncherControllerTest,ExistingBrowserWindowShelfIDSet)4059 TEST_F(ChromeLauncherControllerTest, ExistingBrowserWindowShelfIDSet) {
4060   InitLauncherControllerWithBrowser();
4061   launcher_controller_->PinAppWithID("1");
4062 
4063   TabStripModel* tab_strip_model = browser()->tab_strip_model();
4064   ASSERT_EQ(1, tab_strip_model->count());
4065 
4066   TestLauncherControllerHelper* helper = new TestLauncherControllerHelper;
4067   helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "0");
4068   SetLauncherControllerHelper(helper);
4069 
4070   RecreateLauncherController();
4071   helper = new TestLauncherControllerHelper(profile());
4072   helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
4073   SetLauncherControllerHelper(helper);
4074   launcher_controller_->Init();
4075 
4076   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID("1")));
4077   EXPECT_EQ(ash::ShelfID("1"),
4078             ash::ShelfID::Deserialize(
4079                 browser()->window()->GetNativeWindow()->GetProperty(
4080                     ash::kShelfIDKey)));
4081 }
4082 
TEST_F(ChromeLauncherControllerTest,MultipleAppIconLoaders)4083 TEST_F(ChromeLauncherControllerTest, MultipleAppIconLoaders) {
4084   InitLauncherControllerWithBrowser();
4085 
4086   const ash::ShelfID shelf_id1(extension1_->id());
4087   const ash::ShelfID shelf_id2(extension2_->id());
4088   const ash::ShelfID shelf_id3(extension_gmail_app_->id());
4089   // app_icon_loader1 and app_icon_loader2 are owned by
4090   // ChromeLauncherController.
4091   TestAppIconLoaderImpl* app_icon_loader1 = new TestAppIconLoaderImpl();
4092   TestAppIconLoaderImpl* app_icon_loader2 = new TestAppIconLoaderImpl();
4093   app_icon_loader1->AddSupportedApp(shelf_id1.app_id);
4094   app_icon_loader2->AddSupportedApp(shelf_id2.app_id);
4095   SetAppIconLoaders(std::unique_ptr<AppIconLoader>(app_icon_loader1),
4096                     std::unique_ptr<AppIconLoader>(app_icon_loader2));
4097 
4098   launcher_controller_->CreateAppLauncherItem(
4099       std::make_unique<AppServiceAppWindowLauncherItemController>(
4100           shelf_id3, launcher_controller_->app_service_app_window_controller()),
4101       ash::STATUS_RUNNING);
4102   EXPECT_EQ(0, app_icon_loader1->fetch_count());
4103   EXPECT_EQ(0, app_icon_loader1->clear_count());
4104   EXPECT_EQ(0, app_icon_loader2->fetch_count());
4105   EXPECT_EQ(0, app_icon_loader2->clear_count());
4106 
4107   launcher_controller_->CreateAppLauncherItem(
4108       std::make_unique<AppServiceAppWindowLauncherItemController>(
4109           shelf_id2, launcher_controller_->app_service_app_window_controller()),
4110       ash::STATUS_RUNNING);
4111   EXPECT_EQ(0, app_icon_loader1->fetch_count());
4112   EXPECT_EQ(0, app_icon_loader1->clear_count());
4113   EXPECT_EQ(1, app_icon_loader2->fetch_count());
4114   EXPECT_EQ(0, app_icon_loader2->clear_count());
4115 
4116   launcher_controller_->CreateAppLauncherItem(
4117       std::make_unique<AppServiceAppWindowLauncherItemController>(
4118           shelf_id1, launcher_controller_->app_service_app_window_controller()),
4119       ash::STATUS_RUNNING);
4120   EXPECT_EQ(1, app_icon_loader1->fetch_count());
4121   EXPECT_EQ(0, app_icon_loader1->clear_count());
4122   EXPECT_EQ(1, app_icon_loader2->fetch_count());
4123   EXPECT_EQ(0, app_icon_loader2->clear_count());
4124 
4125   launcher_controller_->CloseLauncherItem(shelf_id1);
4126   EXPECT_EQ(1, app_icon_loader1->fetch_count());
4127   EXPECT_EQ(1, app_icon_loader1->clear_count());
4128   EXPECT_EQ(1, app_icon_loader2->fetch_count());
4129   EXPECT_EQ(0, app_icon_loader2->clear_count());
4130 
4131   launcher_controller_->CloseLauncherItem(shelf_id2);
4132   EXPECT_EQ(1, app_icon_loader1->fetch_count());
4133   EXPECT_EQ(1, app_icon_loader1->clear_count());
4134   EXPECT_EQ(1, app_icon_loader2->fetch_count());
4135   EXPECT_EQ(1, app_icon_loader2->clear_count());
4136 
4137   launcher_controller_->CloseLauncherItem(shelf_id3);
4138   EXPECT_EQ(1, app_icon_loader1->fetch_count());
4139   EXPECT_EQ(1, app_icon_loader1->clear_count());
4140   EXPECT_EQ(1, app_icon_loader2->fetch_count());
4141   EXPECT_EQ(1, app_icon_loader2->clear_count());
4142 }
4143 
TEST_F(ChromeLauncherControllerWithArcTest,ArcAppPinPolicy)4144 TEST_F(ChromeLauncherControllerWithArcTest, ArcAppPinPolicy) {
4145   InitLauncherControllerWithBrowser();
4146   arc::mojom::AppInfo appinfo =
4147       CreateAppInfo("Some App", "SomeActivity", "com.example.app");
4148   const std::string app_id = AddArcAppAndShortcut(appinfo);
4149 
4150   // Set policy, that makes pins ARC app. Unlike native extension, for ARC app
4151   // package_name (not hash) specified as id. In this test we check that
4152   // by hash we can determine that appropriate package was set by policy.
4153   base::ListValue policy_value;
4154   AppendPrefValue(&policy_value, appinfo.package_name);
4155   profile()->GetTestingPrefService()->SetManagedPref(
4156       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
4157 
4158   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
4159   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4160             GetPinnableForAppID(app_id, profile()));
4161 }
4162 
TEST_F(ChromeLauncherControllerWithArcTest,ArcManaged)4163 TEST_F(ChromeLauncherControllerWithArcTest, ArcManaged) {
4164   extension_service_->AddExtension(arc_support_host_.get());
4165   // Test enables ARC, so turn it off for initial values.
4166   EnablePlayStore(false);
4167 
4168   InitLauncherController();
4169 
4170   // To prevent import legacy pins each time.
4171   // Initially pins are imported from legacy pref based model.
4172   StartPrefSyncService(syncer::SyncDataList());
4173 
4174   // Initial run, ARC is not managed and disabled, Play Store pin should be
4175   // available.
4176   ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
4177                    "Chrome, Play Store");
4178 
4179   // ARC is managed and enabled, Play Store pin should be available.
4180   // Note: CHECKING_ANDROID_MANAGEMENT here means that opt-in flow is skipped.
4181   profile()->GetTestingPrefService()->SetManagedPref(
4182       arc::prefs::kArcEnabled, std::make_unique<base::Value>(true));
4183   base::RunLoop().RunUntilIdle();
4184   ValidateArcState(true, true,
4185                    arc::ArcSessionManager::State::CHECKING_ANDROID_MANAGEMENT,
4186                    "Chrome, Play Store");
4187 
4188   // ARC is managed and disabled, Play Store pin should not be available.
4189   profile()->GetTestingPrefService()->SetManagedPref(
4190       arc::prefs::kArcEnabled, std::make_unique<base::Value>(false));
4191   base::RunLoop().RunUntilIdle();
4192   ValidateArcState(false, true, arc::ArcSessionManager::State::STOPPED,
4193                    "Chrome");
4194 
4195   // ARC is not managed and disabled, Play Store pin should be available.
4196   profile()->GetTestingPrefService()->RemoveManagedPref(
4197       arc::prefs::kArcEnabled);
4198   base::RunLoop().RunUntilIdle();
4199   ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
4200                    "Chrome, Play Store");
4201 
4202   // ARC is not managed and enabled, Play Store pin should be available.
4203   // Note: NEGOTIATING_TERMS_OF_SERVICE here means that opt-in flow starts.
4204   EnablePlayStore(true);
4205   ValidateArcState(true, false,
4206                    arc::ArcSessionManager::State::NEGOTIATING_TERMS_OF_SERVICE,
4207                    "Chrome, Play Store");
4208 
4209   // User disables ARC. ARC is not managed and disabled, Play Store pin should
4210   // be automatically removed.
4211   EnablePlayStore(false);
4212   ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
4213                    "Chrome");
4214 
4215   // Even if re-enable it again, Play Store pin does not appear automatically.
4216   EnablePlayStore(true);
4217   ValidateArcState(true, false,
4218                    arc::ArcSessionManager::State::NEGOTIATING_TERMS_OF_SERVICE,
4219                    "Chrome");
4220 }
4221 
4222 // Test the application menu of a shelf item with multiple ARC windows.
TEST_F(ChromeLauncherControllerWithArcTest,ShelfItemWithMultipleWindows)4223 TEST_F(ChromeLauncherControllerWithArcTest, ShelfItemWithMultipleWindows) {
4224   InitLauncherControllerWithBrowser();
4225 
4226   arc::mojom::AppInfo appinfo =
4227       CreateAppInfo("Test1", "test", "com.example.app");
4228   AddArcAppAndShortcut(appinfo);
4229 
4230   // Widgets will be deleted by the system.
4231   NotifyOnTaskCreated(appinfo, 1 /* task_id */);
4232   views::Widget* window1 = CreateArcWindow("org.chromium.arc.1");
4233   ASSERT_TRUE(window1);
4234   EXPECT_TRUE(window1->IsActive());
4235 
4236   NotifyOnTaskCreated(appinfo, 2 /* task_id */);
4237   views::Widget* window2 = CreateArcWindow("org.chromium.arc.2");
4238   ASSERT_TRUE(window2);
4239 
4240   EXPECT_FALSE(window1->IsActive());
4241   EXPECT_TRUE(window2->IsActive());
4242 
4243   const std::string app_id = ArcAppTest::GetAppId(appinfo);
4244   ash::ShelfItemDelegate* item_delegate =
4245       model_->GetShelfItemDelegate(ash::ShelfID(app_id));
4246   ASSERT_TRUE(item_delegate);
4247 
4248   // Selecting the item will show its application menu. It does not change the
4249   // active window.
4250   SelectItem(item_delegate);
4251   EXPECT_FALSE(window1->IsActive());
4252   EXPECT_TRUE(window2->IsActive());
4253 
4254   // Command ids are just app window indices. Note, apps are registered in
4255   // opposite order. Last created goes in front.
4256   auto items = item_delegate->GetAppMenuItems(0, base::NullCallback());
4257   ASSERT_EQ(items.size(), 2U);
4258 
4259   // Execute command 1 to activate the first window.
4260   item_delegate->ExecuteCommand(false, 1, ui::EF_NONE,
4261                                 display::kInvalidDisplayId);
4262   EXPECT_TRUE(window1->IsActive());
4263   EXPECT_FALSE(window2->IsActive());
4264 
4265   // Selecting the item will show its application menu. It does not change the
4266   // active window.
4267   SelectItem(item_delegate);
4268   EXPECT_TRUE(window1->IsActive());
4269   EXPECT_FALSE(window2->IsActive());
4270 
4271   // Execute command 0 to activate the second window.
4272   item_delegate->ExecuteCommand(false, 0, ui::EF_NONE,
4273                                 display::kInvalidDisplayId);
4274   EXPECT_FALSE(window1->IsActive());
4275   EXPECT_TRUE(window2->IsActive());
4276 }
4277 
4278 namespace {
4279 
4280 class ChromeLauncherControllerArcDefaultAppsTest
4281     : public ChromeLauncherControllerTest {
4282  public:
4283   ChromeLauncherControllerArcDefaultAppsTest() = default;
4284   ChromeLauncherControllerArcDefaultAppsTest(
4285       const ChromeLauncherControllerArcDefaultAppsTest&) = delete;
4286   ChromeLauncherControllerArcDefaultAppsTest& operator=(
4287       const ChromeLauncherControllerArcDefaultAppsTest&) = delete;
4288   ~ChromeLauncherControllerArcDefaultAppsTest() override = default;
4289 
4290  protected:
SetUp()4291   void SetUp() override {
4292     ArcAppIcon::DisableSafeDecodingForTesting();
4293     ArcDefaultAppList::UseTestAppsDirectory();
4294     ChromeLauncherControllerTest::SetUp();
4295   }
4296 };
4297 
4298 class ChromeLauncherControllerPlayStoreAvailabilityTest
4299     : public ChromeLauncherControllerTest,
4300       public ::testing::WithParamInterface<bool> {
4301  public:
4302   ChromeLauncherControllerPlayStoreAvailabilityTest() = default;
4303   ChromeLauncherControllerPlayStoreAvailabilityTest(
4304       const ChromeLauncherControllerPlayStoreAvailabilityTest&) = delete;
4305   ChromeLauncherControllerPlayStoreAvailabilityTest& operator=(
4306       const ChromeLauncherControllerPlayStoreAvailabilityTest&) = delete;
4307   ~ChromeLauncherControllerPlayStoreAvailabilityTest() override = default;
4308 
4309  protected:
SetUp()4310   void SetUp() override {
4311     if (GetParam())
4312       arc::SetArcAlwaysStartWithoutPlayStoreForTesting();
4313     // To prevent crash on test exit and pending decode request.
4314     ArcAppIcon::DisableSafeDecodingForTesting();
4315     ArcDefaultAppList::UseTestAppsDirectory();
4316     ChromeLauncherControllerTest::SetUp();
4317   }
4318 };
4319 
4320 }  // namespace
4321 
TEST_F(ChromeLauncherControllerArcDefaultAppsTest,DefaultApps)4322 TEST_F(ChromeLauncherControllerArcDefaultAppsTest, DefaultApps) {
4323   arc_test_.SetUp(profile());
4324   InitLauncherController();
4325 
4326   ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
4327   EnablePlayStore(false);
4328   EXPECT_FALSE(arc::IsArcPlayStoreEnabledForProfile(profile()));
4329   ASSERT_TRUE(prefs->GetAppIds().size());
4330 
4331   const std::string app_id =
4332       ArcAppTest::GetAppId(arc_test_.fake_default_apps()[0]);
4333   const ash::ShelfID shelf_id(app_id);
4334   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4335   EXPECT_TRUE(arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON,
4336                              arc::UserInteractionType::NOT_USER_INITIATED));
4337   EXPECT_TRUE(arc::IsArcPlayStoreEnabledForProfile(profile()));
4338   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
4339 
4340   // Stop ARC again. Shelf item should go away.
4341   EnablePlayStore(false);
4342 
4343   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4344 
4345   EXPECT_TRUE(arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON,
4346                              arc::UserInteractionType::NOT_USER_INITIATED));
4347   EXPECT_TRUE(arc::IsArcPlayStoreEnabledForProfile(profile()));
4348   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
4349 
4350   auto* item_delegate = model_->GetShelfItemDelegate(shelf_id);
4351   ASSERT_TRUE(item_delegate);
4352   EXPECT_TRUE(
4353       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
4354   // Initially, a default icon is set for the shelf item.
4355   EXPECT_FALSE(item_delegate->image_set_by_controller());
4356   auto get_icon = [=]() {
4357     return *launcher_controller_->GetItem(shelf_id)->image.bitmap();
4358   };
4359   const SkBitmap default_icon = get_icon();
4360 
4361   std::string window_app_id("org.chromium.arc.1");
4362   CreateArcWindow(window_app_id);
4363   arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_default_apps()[0],
4364                                             std::string());
4365   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
4366   // Refresh delegate, it was changed.
4367   item_delegate = model_->GetShelfItemDelegate(shelf_id);
4368   ASSERT_TRUE(item_delegate);
4369   EXPECT_FALSE(
4370       launcher_controller_->GetShelfSpinnerController()->HasApp(app_id));
4371   EXPECT_FALSE(item_delegate->image_set_by_controller());
4372   EXPECT_TRUE(gfx::test::AreBitmapsEqual(default_icon, get_icon()));
4373 
4374   // Wait for the real app icon image to be decoded and set for the shelf item.
4375   base::RunLoop().RunUntilIdle();
4376   EXPECT_FALSE(gfx::test::AreBitmapsEqual(default_icon, get_icon()));
4377 }
4378 
TEST_F(ChromeLauncherControllerArcDefaultAppsTest,PlayStoreDeferredLaunch)4379 TEST_F(ChromeLauncherControllerArcDefaultAppsTest, PlayStoreDeferredLaunch) {
4380   // Add ARC host app to enable Play Store default app.
4381   extension_service_->AddExtension(arc_support_host_.get());
4382   arc_test_.SetUp(profile());
4383   ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
4384   EXPECT_TRUE(prefs->IsRegistered(arc::kPlayStoreAppId));
4385 
4386   InitLauncherController();
4387 
4388   EnablePlayStore(true);
4389 
4390   // Pin Play Store. It should be pinned but not scheduled for deferred launch.
4391   launcher_controller_->PinAppWithID(arc::kPlayStoreAppId);
4392   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
4393   EXPECT_FALSE(launcher_controller_->GetShelfSpinnerController()->HasApp(
4394       arc::kPlayStoreAppId));
4395 
4396   // Simulate click. This should schedule Play Store for deferred launch.
4397   ash::ShelfItemDelegate* item_delegate =
4398       model_->GetShelfItemDelegate(ash::ShelfID(arc::kPlayStoreAppId));
4399   EXPECT_TRUE(item_delegate);
4400   SelectItem(item_delegate);
4401   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
4402   EXPECT_TRUE(launcher_controller_->GetShelfSpinnerController()->HasApp(
4403       arc::kPlayStoreAppId));
4404 }
4405 
TEST_F(ChromeLauncherControllerArcDefaultAppsTest,PlayStoreLaunchMetric)4406 TEST_F(ChromeLauncherControllerArcDefaultAppsTest, PlayStoreLaunchMetric) {
4407   extension_service_->AddExtension(arc_support_host_.get());
4408   arc_test_.SetUp(profile());
4409   ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
4410 
4411   InitLauncherController();
4412   EnablePlayStore(true);
4413 
4414   // Play Store available now as a default app but is not ready yet.
4415   std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
4416       prefs->GetApp(arc::kPlayStoreAppId);
4417   ASSERT_TRUE(app_info);
4418   EXPECT_FALSE(app_info->ready);
4419 
4420   constexpr char kHistogramName[] = "Arc.PlayStoreLaunch.TimeDelta";
4421 
4422   // Launch Play Store in deferred mode.
4423   arc::LaunchApp(profile(), arc::kPlayStoreAppId, ui::EF_LEFT_MOUSE_BUTTON,
4424                  arc::UserInteractionType::NOT_USER_INITIATED);
4425   // This is deferred launch, no actual intents are delivered to ARC.
4426   EXPECT_EQ(0U, arc_test_.app_instance()->launch_intents().size());
4427   arc::mojom::AppInfo app;
4428   app.activity = arc::kPlayStoreActivity;
4429   app.package_name = arc::kPlayStorePackage;
4430   arc_test_.app_instance()->SendRefreshAppList({app});
4431   ASSERT_EQ(1U, arc_test_.app_instance()->launch_intents().size());
4432   std::string play_store_window_id("org.chromium.arc.1");
4433   views::Widget* play_store_window = CreateArcWindow(play_store_window_id);
4434   arc_test_.app_instance()->SendTaskCreated(
4435       1, app, arc_test_.app_instance()->launch_intents()[0]);
4436   EXPECT_TRUE(
4437       launcher_controller_->GetItem(ash::ShelfID(arc::kPlayStoreAppId)));
4438   // UMA is reported since app becomes ready.
4439   base::HistogramBase* const histogram =
4440       base::StatisticsRecorder::FindHistogram(kHistogramName);
4441   ASSERT_TRUE(histogram);
4442   std::unique_ptr<base::HistogramSamples> samples = histogram->SnapshotDelta();
4443   ASSERT_EQ(1, samples->TotalCount());
4444   play_store_window->Close();
4445 
4446   // Launch Play Store in app-ready mode.
4447   arc::LaunchApp(profile(), arc::kPlayStoreAppId, ui::EF_LEFT_MOUSE_BUTTON,
4448                  arc::UserInteractionType::NOT_USER_INITIATED);
4449   ASSERT_EQ(2U, arc_test_.app_instance()->launch_intents().size());
4450   play_store_window_id = "org.chromium.arc.2";
4451   play_store_window = CreateArcWindow(play_store_window_id);
4452   arc_test_.app_instance()->SendTaskCreated(
4453       2, app, arc_test_.app_instance()->launch_intents()[1]);
4454   EXPECT_TRUE(
4455       launcher_controller_->GetItem(ash::ShelfID(arc::kPlayStoreAppId)));
4456   // UMA is reported for app-ready launch. Note, previous call of SnapshotDelta
4457   // resets samples, so we expect here only one recorded.
4458   EXPECT_EQ(1, histogram->SnapshotDelta()->TotalCount());
4459   play_store_window->Close();
4460 }
4461 
4462 // Tests that the Play Store is not visible in AOSP image and visible in default
4463 // images.
TEST_P(ChromeLauncherControllerPlayStoreAvailabilityTest,Visible)4464 TEST_P(ChromeLauncherControllerPlayStoreAvailabilityTest, Visible) {
4465   extension_service_->AddExtension(arc_support_host_.get());
4466   arc_test_.SetUp(profile());
4467 
4468   InitLauncherController();
4469   StartPrefSyncService(syncer::SyncDataList());
4470 
4471   ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
4472   EXPECT_EQ(arc::IsPlayStoreAvailable(),
4473             prefs->IsRegistered(arc::kPlayStoreAppId));
4474   // If the Play Store available, it is pinned by default.
4475   EXPECT_EQ(arc::IsPlayStoreAvailable(),
4476             launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
4477   arc_test_.TearDown();
4478 }
4479 
4480 // Checks the case when several app items have the same ordinal position (which
4481 // is valid case).
TEST_F(ChromeLauncherControllerTest,CheckPositionConflict)4482 TEST_F(ChromeLauncherControllerTest, CheckPositionConflict) {
4483   InitLauncherController();
4484 
4485   extension_service_->AddExtension(extension1_.get());
4486   extension_service_->AddExtension(extension2_.get());
4487   extension_service_->AddExtension(extension_gmail_app_.get());
4488 
4489   syncer::SyncChangeList sync_list;
4490   InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
4491   InsertAddPinChange(&sync_list, 1, extension1_->id());
4492   InsertAddPinChange(&sync_list, 1, extension2_->id());
4493   InsertAddPinChange(&sync_list, 1, extension_gmail_app_->id());
4494   SendPinChanges(sync_list, true);
4495 
4496   EXPECT_EQ("Chrome, App1, App2, Gmail", GetPinnedAppStatus());
4497 
4498   const syncer::StringOrdinal position_chrome =
4499       app_list_syncable_service_->GetPinPosition(extension_misc::kChromeAppId);
4500   const syncer::StringOrdinal position_1 =
4501       app_list_syncable_service_->GetPinPosition(extension1_->id());
4502   const syncer::StringOrdinal position_2 =
4503       app_list_syncable_service_->GetPinPosition(extension2_->id());
4504   const syncer::StringOrdinal position_3 =
4505       app_list_syncable_service_->GetPinPosition(extension_gmail_app_->id());
4506   EXPECT_TRUE(position_chrome.LessThan(position_1));
4507   EXPECT_TRUE(position_1.Equals(position_2));
4508   EXPECT_TRUE(position_2.Equals(position_3));
4509 
4510   // Move Chrome between App1 and App2.
4511   // Note, move target_index is in context when moved element is removed from
4512   // array first.
4513   model_->Move(0, 1);
4514   EXPECT_EQ("App1, Chrome, App2, Gmail", GetPinnedAppStatus());
4515 
4516   // Expect sync positions for only Chrome is updated and its resolution is
4517   // after all duplicated ordinals.
4518   EXPECT_TRUE(position_3.LessThan(app_list_syncable_service_->GetPinPosition(
4519       extension_misc::kChromeAppId)));
4520   EXPECT_TRUE(position_1.Equals(
4521       app_list_syncable_service_->GetPinPosition(extension1_->id())));
4522   EXPECT_TRUE(position_1.Equals(
4523       app_list_syncable_service_->GetPinPosition(extension1_->id())));
4524   EXPECT_TRUE(position_2.Equals(
4525       app_list_syncable_service_->GetPinPosition(extension2_->id())));
4526   EXPECT_TRUE(position_3.Equals(
4527       app_list_syncable_service_->GetPinPosition(extension_gmail_app_->id())));
4528 }
4529 
4530 // Test the case when sync app is turned off and we need to use local copy to
4531 // support user's pins.
TEST_F(ChromeLauncherControllerTest,SyncOffLocalUpdate)4532 TEST_F(ChromeLauncherControllerTest, SyncOffLocalUpdate) {
4533   InitLauncherController();
4534 
4535   extension_service_->AddExtension(extension1_.get());
4536   extension_service_->AddExtension(extension2_.get());
4537 
4538   syncer::SyncChangeList sync_list;
4539   InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
4540   InsertAddPinChange(&sync_list, 1, extension1_->id());
4541   InsertAddPinChange(&sync_list, 1, extension2_->id());
4542   SendPinChanges(sync_list, true);
4543 
4544   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
4545 
4546   syncer::SyncDataList copy_sync_list =
4547       app_list_syncable_service_->GetAllSyncDataForTesting();
4548 
4549   app_list_syncable_service_->StopSyncing(syncer::APP_LIST);
4550   RecreateLauncherController()->Init();
4551 
4552   // Pinned state should not change.
4553   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
4554   launcher_controller_->UnpinAppWithID(extension2_->id());
4555   EXPECT_EQ("Chrome, App1", GetPinnedAppStatus());
4556 
4557   // Resume syncing and sync information overrides local copy.
4558   StartAppSyncService(copy_sync_list);
4559   EXPECT_EQ("Chrome, App1, App2", GetPinnedAppStatus());
4560 }
4561 
4562 // Test the Settings can be pinned and unpinned.
TEST_F(ChromeLauncherControllerTest,InternalAppPinUnpin)4563 TEST_F(ChromeLauncherControllerTest, InternalAppPinUnpin) {
4564   InitLauncherController();
4565   // The model should only contain the browser shortcut item.
4566   EXPECT_EQ(1, model_->item_count());
4567 
4568   const std::string app_id = ash::kInternalAppIdSettings;
4569   EXPECT_FALSE(launcher_controller_->IsAppPinned(app_id));
4570 
4571   // Pin Settings.
4572   launcher_controller_->PinAppWithID(app_id);
4573   EXPECT_EQ(2, model_->item_count());
4574   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
4575   EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[1].status);
4576   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
4577 
4578   // Unpin Settings.
4579   launcher_controller_->UnpinAppWithID(app_id);
4580   EXPECT_EQ(1, model_->item_count());
4581   EXPECT_FALSE(launcher_controller_->IsAppPinned(app_id));
4582 }
4583 
4584 // Test that internal app can be added and removed on shelf.
TEST_F(ChromeLauncherControllerTest,InternalAppWindowRecreation)4585 TEST_F(ChromeLauncherControllerTest, InternalAppWindowRecreation) {
4586   InitLauncherController();
4587 
4588   // Only test the first internal app. The others should be the same.
4589   const auto& internal_app = app_list::GetInternalAppList(profile()).front();
4590   const std::string app_id = internal_app.app_id;
4591   const ash::ShelfID shelf_id(app_id);
4592   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4593 
4594   views::Widget* internal_app_window = CreateShelfAppWindow(app_id);
4595   ASSERT_TRUE(internal_app_window);
4596   base::RunLoop().RunUntilIdle();
4597   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
4598 
4599   internal_app_window->Close();
4600   base::RunLoop().RunUntilIdle();
4601   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4602 
4603   // Create and close again.
4604   internal_app_window = CreateShelfAppWindow(app_id);
4605   ASSERT_TRUE(internal_app_window);
4606   base::RunLoop().RunUntilIdle();
4607   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
4608 
4609   internal_app_window->Close();
4610   base::RunLoop().RunUntilIdle();
4611   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4612 }
4613 
4614 // Test that internal app can be added and removed by SetProperty of
4615 // ash::kShelfIDKey.
TEST_F(ChromeLauncherControllerTest,InternalAppWindowPropertyChanged)4616 TEST_F(ChromeLauncherControllerTest, InternalAppWindowPropertyChanged) {
4617   InitLauncherController();
4618 
4619   // Only test the first internal app. The others should be the same.
4620   const auto internal_app = app_list::GetInternalAppList(profile()).front();
4621   std::string app_id;
4622   ash::ShelfID shelf_id;
4623   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4624 
4625   // Set an empty ash::kShelfIDKey.
4626   views::Widget* internal_app_window = CreateShelfAppWindow(app_id);
4627   ASSERT_TRUE(internal_app_window);
4628   base::RunLoop().RunUntilIdle();
4629   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4630 
4631   // Set an invalid ash::kShelfIDKey.
4632   app_id = "An invalid internal app id";
4633   shelf_id = ash::ShelfID(app_id);
4634   internal_app_window->GetNativeWindow()->SetProperty(
4635       ash::kShelfIDKey, new std::string(shelf_id.Serialize()));
4636   base::RunLoop().RunUntilIdle();
4637   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4638 
4639   // Set a valid ash::kShelfIDKey.
4640   app_id = internal_app.app_id;
4641   shelf_id = ash::ShelfID(app_id);
4642   internal_app_window->GetNativeWindow()->SetProperty(
4643       ash::kShelfIDKey, new std::string(shelf_id.Serialize()));
4644   base::RunLoop().RunUntilIdle();
4645   EXPECT_TRUE(launcher_controller_->GetItem(shelf_id));
4646 
4647   internal_app_window->Close();
4648   base::RunLoop().RunUntilIdle();
4649   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
4650 }
4651 
4652 class ChromeLauncherControllerDemoModeTest
4653     : public ChromeLauncherControllerTest {
4654  protected:
ChromeLauncherControllerDemoModeTest()4655   ChromeLauncherControllerDemoModeTest() { auto_start_arc_test_ = true; }
4656   ChromeLauncherControllerDemoModeTest(
4657       const ChromeLauncherControllerDemoModeTest&) = delete;
4658   ChromeLauncherControllerDemoModeTest& operator=(
4659       const ChromeLauncherControllerDemoModeTest&) = delete;
4660   ~ChromeLauncherControllerDemoModeTest() override = default;
4661 
SetUp()4662   void SetUp() override {
4663     // To prevent crash on test exit and pending decode request.
4664     ArcAppIcon::DisableSafeDecodingForTesting();
4665 
4666     ChromeLauncherControllerTest::SetUp();
4667 
4668     // Fake Demo Mode.
4669     demo_mode_test_helper_ = std::make_unique<chromeos::DemoModeTestHelper>();
4670     demo_mode_test_helper_->InitializeSession();
4671   }
4672 
TearDown()4673   void TearDown() override {
4674     demo_mode_test_helper_.reset();
4675 
4676     ChromeLauncherControllerTest::TearDown();
4677   }
4678 
4679  private:
4680   std::unique_ptr<chromeos::DemoModeTestHelper> demo_mode_test_helper_;
4681 };
4682 
TEST_F(ChromeLauncherControllerDemoModeTest,PinnedAppsOnline)4683 TEST_F(ChromeLauncherControllerDemoModeTest, PinnedAppsOnline) {
4684   network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
4685       network::mojom::ConnectionType::CONNECTION_ETHERNET);
4686 
4687   InitLauncherControllerWithBrowser();
4688 
4689   base::ListValue policy_value;
4690 
4691   extension_service_->AddExtension(extension1_.get());
4692   extension_service_->AddExtension(extension2_.get());
4693   AppendPrefValue(&policy_value, extension1_->id());
4694   AppendPrefValue(&policy_value, extension2_->id());
4695 
4696   arc::mojom::AppInfo appinfo =
4697       CreateAppInfo("Some App", "SomeActivity", "com.example.app");
4698   const std::string app_id = AddArcAppAndShortcut(appinfo);
4699 
4700   arc::mojom::AppInfo online_only_appinfo =
4701       CreateAppInfo("Some App", "SomeActivity", "com.example.onlineonly");
4702   const std::string online_only_app_id =
4703       AddArcAppAndShortcut(online_only_appinfo);
4704 
4705   AppendPrefValue(&policy_value, appinfo.package_name);
4706   AppendPrefValue(&policy_value, online_only_appinfo.package_name);
4707 
4708   // If the device is offline, extension2 and onlineonly should be unpinned.
4709   chromeos::DemoSession::Get()->OverrideIgnorePinPolicyAppsForTesting(
4710       {extension2_->id(), online_only_appinfo.package_name});
4711 
4712   profile()->GetTestingPrefService()->SetManagedPref(
4713       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
4714 
4715   app_service_test().FlushMojoCalls();
4716 
4717   // Since the device is online, all policy pinned apps are pinned.
4718   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
4719   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4720             GetPinnableForAppID(extension1_->id(), profile()));
4721 
4722   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
4723   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4724             GetPinnableForAppID(extension2_->id(), profile()));
4725 
4726   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
4727   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4728             GetPinnableForAppID(app_id, profile()));
4729 
4730   EXPECT_TRUE(launcher_controller_->IsAppPinned(online_only_app_id));
4731   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4732             GetPinnableForAppID(online_only_app_id, profile()));
4733 }
4734 
TEST_F(ChromeLauncherControllerDemoModeTest,PinnedAppsOffline)4735 TEST_F(ChromeLauncherControllerDemoModeTest, PinnedAppsOffline) {
4736   network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
4737       network::mojom::ConnectionType::CONNECTION_NONE);
4738 
4739   InitLauncherControllerWithBrowser();
4740 
4741   base::ListValue policy_value;
4742 
4743   extension_service_->AddExtension(extension1_.get());
4744   extension_service_->AddExtension(extension2_.get());
4745   AppendPrefValue(&policy_value, extension1_->id());
4746   AppendPrefValue(&policy_value, extension2_->id());
4747 
4748   arc::mojom::AppInfo appinfo =
4749       CreateAppInfo("Some App", "SomeActivity", "com.example.app");
4750   const std::string app_id = AddArcAppAndShortcut(appinfo);
4751 
4752   arc::mojom::AppInfo online_only_appinfo =
4753       CreateAppInfo("Some App", "SomeActivity", "com.example.onlineonly");
4754   const std::string online_only_app_id =
4755       AddArcAppAndShortcut(online_only_appinfo);
4756 
4757   AppendPrefValue(&policy_value, appinfo.package_name);
4758   AppendPrefValue(&policy_value, online_only_appinfo.package_name);
4759 
4760   // If the device is offline, extension2 and onlineonly should be unpinned.
4761   chromeos::DemoSession::Get()->OverrideIgnorePinPolicyAppsForTesting(
4762       {extension2_->id(), online_only_appinfo.package_name});
4763 
4764   profile()->GetTestingPrefService()->SetManagedPref(
4765       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
4766   app_service_test().FlushMojoCalls();
4767 
4768   // Since the device is online, the policy pinned apps that shouldn't be pinned
4769   // in Demo Mode are unpinned.
4770   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
4771   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4772             GetPinnableForAppID(extension1_->id(), profile()));
4773 
4774   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
4775   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
4776             GetPinnableForAppID(extension2_->id(), profile()));
4777 
4778   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
4779   EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
4780             GetPinnableForAppID(app_id, profile()));
4781 
4782   EXPECT_FALSE(launcher_controller_->IsAppPinned(online_only_app_id));
4783   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
4784             GetPinnableForAppID(online_only_app_id, profile()));
4785 
4786   // Pin a Chrome app that would have been pinned by policy but was suppressed
4787   // for Demo Mode.
4788   launcher_controller_->PinAppWithID(extension2_->id());
4789   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
4790   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
4791             GetPinnableForAppID(extension2_->id(), profile()));
4792 
4793   // Pin an ARC app that would have been pinned by policy but was suppressed
4794   // for Demo Mode.
4795   launcher_controller_->PinAppWithID(online_only_app_id);
4796   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
4797   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
4798             GetPinnableForAppID(online_only_app_id, profile()));
4799 }
4800 
TEST_F(ChromeLauncherControllerTest,CrostiniTerminalPinUnpin)4801 TEST_F(ChromeLauncherControllerTest, CrostiniTerminalPinUnpin) {
4802   InitLauncherController();
4803 
4804   // Load pinned Terminal from prefs without Crostini UI being allowed
4805   syncer::SyncChangeList sync_list;
4806   InsertAddPinChange(&sync_list, 1, crostini::kCrostiniTerminalSystemAppId);
4807   SendPinChanges(sync_list, true);
4808   EXPECT_EQ("Chrome", GetPinnedAppStatus());
4809 
4810   // Reload after allowing Crostini UI
4811   crostini::CrostiniTestHelper test_helper(profile());
4812   test_helper.ReInitializeAppServiceIntegration();
4813   // TODO(crubug.com/918739): Fix pins are not refreshed on enabling Crostini.
4814   // As a workaround add any app that triggers pin update.
4815   AddExtension(extension1_.get());
4816   EXPECT_EQ("Chrome, Terminal", GetPinnedAppStatus());
4817 
4818   // Unpin the Terminal
4819   launcher_controller_->UnpinAppWithID(crostini::kCrostiniTerminalSystemAppId);
4820   EXPECT_EQ("Chrome", GetPinnedAppStatus());
4821 
4822   // Pin Terminal again.
4823   launcher_controller_->PinAppWithID(crostini::kCrostiniTerminalSystemAppId);
4824   EXPECT_EQ("Chrome, Terminal", GetPinnedAppStatus());
4825 }
4826 
4827 // TODO(crbug.com/846546) Recognising app id from the browser app_name is only
4828 // necessary because the crostini terminal is a little hacky. Pending a better
4829 // terminal implementation we should remove this test.
TEST_F(ChromeLauncherControllerTest,CrostiniBrowserWindowsRecogniseShelfItem)4830 TEST_F(ChromeLauncherControllerTest, CrostiniBrowserWindowsRecogniseShelfItem) {
4831   InitLauncherController();
4832   crostini::CrostiniTestHelper helper(profile());
4833 
4834   // We want to match this shelf item.
4835   ash::ShelfItem item;
4836   item.id = ash::ShelfID("blah");
4837   item.type = ash::ShelfItemType::TYPE_APP;
4838   model_->Add(item);
4839 
4840   // We manually create a browser window with the correct app_name, as this is
4841   // how the app_id is communicated.
4842   Browser::CreateParams params = Browser::CreateParams::CreateForApp(
4843       crostini::AppNameFromCrostiniAppId(item.id.app_id),
4844       true /* trusted_srouce */, browser()->window()->GetBounds(), profile(),
4845       true /* user_gesture */);
4846   params.window = browser()->window();
4847   params.type = Browser::TYPE_NORMAL;
4848   Browser* b = Browser::Create(params);
4849   set_browser(b);
4850   chrome::NewTab(browser());
4851   browser()->window()->Show();
4852 
4853   EXPECT_EQ(launcher_controller_->GetAppIDForWebContents(
4854                 browser()->tab_strip_model()->GetActiveWebContents()),
4855             item.id.app_id);
4856 }
4857 
4858 // Tests behavior for ensuring some component apps can be marked unpinnable.
TEST_F(ChromeLauncherControllerTest,UnpinnableComponentApps)4859 TEST_F(ChromeLauncherControllerTest, UnpinnableComponentApps) {
4860   InitLauncherController();
4861 
4862   const char* kPinnableApp = file_manager::kFileManagerAppId;
4863   const char* kNoPinApps[] = {file_manager::kGalleryAppId,
4864                               extension_misc::kFeedbackExtensionId};
4865 
4866   EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
4867             GetPinnableForAppID(kPinnableApp, profile()));
4868   for (const char* id : kNoPinApps) {
4869     EXPECT_EQ(AppListControllerDelegate::NO_PIN,
4870               GetPinnableForAppID(id, profile()));
4871   }
4872 }
4873 
TEST_F(ChromeLauncherControllerTest,DoNotShowInShelf)4874 TEST_F(ChromeLauncherControllerTest, DoNotShowInShelf) {
4875   syncer::SyncChangeList sync_list;
4876   InsertAddPinChange(&sync_list, 0, extension1_->id());
4877   InsertAddPinChange(&sync_list, 0, extension2_->id());
4878   SendPinChanges(sync_list, true);
4879 
4880   AddExtension(extension1_.get());
4881   AddExtension(extension2_.get());
4882 
4883   // Set App1.show_in_shelf to false.
4884   std::vector<apps::mojom::AppPtr> apps;
4885   apps::mojom::AppPtr app = apps::mojom::App::New();
4886   app->app_type = apps::mojom::AppType::kExtension;
4887   app->app_id = extension1_->id();
4888   app->show_in_shelf = apps::mojom::OptionalBool::kFalse;
4889   apps.push_back(std::move(app));
4890   apps::AppServiceProxyFactory::GetForProfile(profile())
4891       ->AppRegistryCache()
4892       .OnApps(std::move(apps));
4893 
4894   InitLauncherController();
4895   EXPECT_EQ("Chrome, App2", GetPinnedAppStatus());
4896 }
4897 
TEST_F(ChromeLauncherControllerWithArcTest,ReplacePinnedItem)4898 TEST_F(ChromeLauncherControllerWithArcTest, ReplacePinnedItem) {
4899   InitLauncherController();
4900   SendListOfArcApps();
4901 
4902   const std::string arc_app_id1 =
4903       ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
4904   const std::string arc_app_id2 =
4905       ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
4906 
4907   extension_service_->AddExtension(extension1_.get());
4908   extension_service_->AddExtension(extension2_.get());
4909 
4910   launcher_controller_->PinAppWithID(extension1_->id());
4911   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
4912   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
4913 
4914   // Replace pin extension to ARC app
4915   launcher_controller_->ReplacePinnedItem(extension1_->id(), arc_app_id1);
4916   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
4917   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
4918 
4919   // Replace pin ARC app to ARC app
4920   launcher_controller_->ReplacePinnedItem(arc_app_id1, arc_app_id2);
4921   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
4922   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
4923 
4924   // Replace pin ARC app to extension app
4925   launcher_controller_->ReplacePinnedItem(arc_app_id2, extension1_->id());
4926   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
4927   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
4928 
4929   // Replace pin extension app to extension app
4930   launcher_controller_->ReplacePinnedItem(extension1_->id(), extension2_->id());
4931   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
4932   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
4933 
4934   // Try to replace item that is not pinned.
4935   launcher_controller_->ReplacePinnedItem(arc_app_id2, extension1_->id());
4936   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
4937   EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
4938 
4939   // Try to replace item with item that is already pinned.
4940   launcher_controller_->PinAppWithID(extension1_->id());
4941   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
4942   launcher_controller_->ReplacePinnedItem(extension2_->id(), extension1_->id());
4943   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
4944   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
4945 }
4946 
TEST_F(ChromeLauncherControllerWithArcTest,PinAtIndex)4947 TEST_F(ChromeLauncherControllerWithArcTest, PinAtIndex) {
4948   InitLauncherController();
4949   SendListOfArcApps();
4950 
4951   const std::string arc_app_id1 =
4952       ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
4953   const std::string arc_app_id2 =
4954       ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
4955 
4956   extension_service_->AddExtension(extension1_.get());
4957   extension_service_->AddExtension(extension2_.get());
4958 
4959   int index = 0;
4960   launcher_controller_->PinAppAtIndex(extension1_->id(), index);
4961   EXPECT_EQ(index,
4962             launcher_controller_->PinnedItemIndexByAppID(extension1_->id()));
4963 
4964   launcher_controller_->PinAppAtIndex(extension2_->id(), index);
4965   EXPECT_EQ(index,
4966             launcher_controller_->PinnedItemIndexByAppID(extension2_->id()));
4967   EXPECT_NE(index,
4968             launcher_controller_->PinnedItemIndexByAppID(extension1_->id()));
4969 
4970   index = 3;
4971   launcher_controller_->PinAppAtIndex(arc_app_id1, index);
4972   EXPECT_EQ(index, launcher_controller_->PinnedItemIndexByAppID(arc_app_id1));
4973 
4974   // Test pinning at invalid index.
4975   index = -100;
4976   launcher_controller_->PinAppAtIndex(arc_app_id2, index);
4977   EXPECT_NE(index, launcher_controller_->PinnedItemIndexByAppID(arc_app_id2));
4978   EXPECT_EQ(-1, launcher_controller_->PinnedItemIndexByAppID(arc_app_id2));
4979 
4980   // Test pinning already pinned app.
4981   index = 0;
4982   launcher_controller_->PinAppAtIndex(arc_app_id1, index);
4983   EXPECT_NE(index, launcher_controller_->PinnedItemIndexByAppID(arc_app_id1));
4984   EXPECT_EQ(3, launcher_controller_->PinnedItemIndexByAppID(arc_app_id1));
4985 }
4986 
4987 class ChromeLauncherControllerWebAppTest : public ChromeLauncherControllerTest {
4988  protected:
ChromeLauncherControllerWebAppTest()4989   ChromeLauncherControllerWebAppTest() {}
4990 
4991   ~ChromeLauncherControllerWebAppTest() override = default;
4992 
MaybeStartWebAppProvider()4993   void MaybeStartWebAppProvider() override {
4994     auto system_web_app_manager =
4995         std::make_unique<web_app::TestSystemWebAppManager>(profile());
4996 
4997     auto* provider = web_app::TestWebAppProvider::Get(profile());
4998     provider->SetSystemWebAppManager(std::move(system_web_app_manager));
4999     provider->SetRunSubsystemStartupTasks(true);
5000     provider->Start();
5001   }
5002 };
5003 
5004 // Test the web app interaction flow: pin it, run it, unpin it, close it.
TEST_F(ChromeLauncherControllerWebAppTest,WebAppPinRunUnpinClose)5005 TEST_F(ChromeLauncherControllerWebAppTest, WebAppPinRunUnpinClose) {
5006   constexpr char kWebAppUrl[] = "https://webappone.com/";
5007   constexpr char kWebAppName[] = "WebApp1";
5008 
5009   InitLauncherController();
5010 
5011   const web_app::AppId app_id =
5012       web_app::InstallDummyWebApp(profile(), kWebAppName, GURL(kWebAppUrl));
5013   base::RunLoop().RunUntilIdle();
5014 
5015   // The model should only contain the browser shortcut item.
5016   EXPECT_EQ(1, model_->item_count());
5017   EXPECT_FALSE(launcher_controller_->IsAppPinned(app_id));
5018   EXPECT_EQ(nullptr, launcher_controller_->GetItem(ash::ShelfID(app_id)));
5019 
5020   // Pinning the app should create a new shelf item.
5021   launcher_controller_->PinAppWithID(app_id);
5022   EXPECT_EQ(2, model_->item_count());
5023   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
5024   EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[1].status);
5025   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
5026   EXPECT_NE(nullptr, launcher_controller_->GetItem(ash::ShelfID(app_id)));
5027 
5028   // Reporting that the app is running should just update the existing item.
5029   launcher_controller_->SetV1AppStatus(app_id, ash::STATUS_RUNNING);
5030   EXPECT_EQ(2, model_->item_count());
5031   EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
5032   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
5033   EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
5034   EXPECT_NE(nullptr, launcher_controller_->GetItem(ash::ShelfID(app_id)));
5035 
5036   // Unpinning the app should just update the existing item.
5037   launcher_controller_->UnpinAppWithID(app_id);
5038   EXPECT_EQ(2, model_->item_count());
5039   EXPECT_EQ(ash::TYPE_APP, model_->items()[1].type);
5040   EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[1].status);
5041   EXPECT_FALSE(launcher_controller_->IsAppPinned(app_id));
5042   EXPECT_NE(nullptr, launcher_controller_->GetItem(ash::ShelfID(app_id)));
5043 
5044   // Reporting that the app is closed should remove its shelf item.
5045   launcher_controller_->SetV1AppStatus(app_id, ash::STATUS_CLOSED);
5046   EXPECT_EQ(1, model_->item_count());
5047   EXPECT_FALSE(launcher_controller_->IsAppPinned(app_id));
5048   EXPECT_EQ(nullptr, launcher_controller_->GetItem(ash::ShelfID(app_id)));
5049 }
5050 
5051 INSTANTIATE_TEST_SUITE_P(All,
5052                          ChromeLauncherControllerPlayStoreAvailabilityTest,
5053                          ::testing::Values(false, true));
5054