Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc

Issue 2839933005: mash: Merge ChromeLauncherController and *Impl subclass. (Closed)
Patch Set: Address comments. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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_impl.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/display/screen_orientation_controller_chromeos.h"
19 #include "ash/public/cpp/app_launch_id.h"
20 #include "ash/public/cpp/shelf_item.h"
21 #include "ash/public/cpp/shelf_item_delegate.h"
22 #include "ash/shelf/shelf_application_menu_model.h"
23 #include "ash/shelf/shelf_constants.h"
24 #include "ash/shelf/shelf_controller.h"
25 #include "ash/shelf/shelf_model.h"
26 #include "ash/shelf/shelf_model_observer.h"
27 #include "ash/shell.h"
28 #include "ash/test/ash_test_helper.h"
29 #include "ash/test/shell_test_api.h"
30 #include "ash/test/test_shell_delegate.h"
31 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
32 #include "ash/wm/window_util.h"
33 #include "base/command_line.h"
34 #include "base/compiler_specific.h"
35 #include "base/files/file_path.h"
36 #include "base/json/json_string_value_serializer.h"
37 #include "base/location.h"
38 #include "base/macros.h"
39 #include "base/memory/ptr_util.h"
40 #include "base/run_loop.h"
41 #include "base/single_thread_task_runner.h"
42 #include "base/strings/utf_string_conversions.h"
43 #include "base/values.h"
44 #include "build/build_config.h"
45 #include "chrome/browser/chromeos/arc/arc_support_host.h"
46 #include "chrome/browser/chromeos/arc/arc_util.h"
47 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
48 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
49 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
50 #include "chrome/browser/extensions/extension_service.h"
51 #include "chrome/browser/extensions/test_extension_system.h"
52 #include "chrome/browser/lifetime/scoped_keep_alive.h"
53 #include "chrome/browser/prefs/browser_prefs.h"
54 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
55 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
56 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
57 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
58 #include "chrome/browser/ui/app_list/arc/arc_default_app_list.h"
59 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
60 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
61 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
62 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h"
63 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
64 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
65 #include "chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_cont roller.h"
66 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h"
67 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
68 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
69 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
70 #include "chrome/browser/ui/browser.h"
71 #include "chrome/browser/ui/browser_commands.h"
72 #include "chrome/browser/ui/browser_finder.h"
73 #include "chrome/browser/ui/browser_list.h"
74 #include "chrome/browser/ui/browser_tabstrip.h"
75 #include "chrome/browser/ui/tabs/tab_strip_model.h"
76 #include "chrome/common/chrome_constants.h"
77 #include "chrome/common/chrome_switches.h"
78 #include "chrome/common/extensions/extension_constants.h"
79 #include "chrome/common/pref_names.h"
80 #include "chrome/test/base/browser_with_test_window_test.h"
81 #include "chrome/test/base/test_browser_window_aura.h"
82 #include "chrome/test/base/testing_browser_process.h"
83 #include "chrome/test/base/testing_profile.h"
84 #include "chrome/test/base/testing_profile_manager.h"
85 #include "chromeos/chromeos_switches.h"
86 #include "components/arc/arc_util.h"
87 #include "components/arc/common/app.mojom.h"
88 #include "components/arc/test/fake_app_instance.h"
89 #include "components/exo/shell_surface.h"
90 #include "components/prefs/pref_notifier_impl.h"
91 #include "components/signin/core/account_id/account_id.h"
92 #include "components/sync/model/attachments/attachment_service_proxy_for_test.h"
93 #include "components/sync/model/fake_sync_change_processor.h"
94 #include "components/sync/model/sync_error_factory_mock.h"
95 #include "components/sync/protocol/sync.pb.h"
96 #include "components/sync_preferences/pref_model_associator.h"
97 #include "components/sync_preferences/testing_pref_service_syncable.h"
98 #include "components/user_manager/fake_user_manager.h"
99 #include "content/public/browser/web_contents.h"
100 #include "content/public/browser/web_contents_observer.h"
101 #include "content/public/test/test_utils.h"
102 #include "content/public/test/web_contents_tester.h"
103 #include "extensions/browser/app_window/app_window_contents.h"
104 #include "extensions/browser/app_window/app_window_registry.h"
105 #include "extensions/browser/app_window/native_app_window.h"
106 #include "extensions/common/extension.h"
107 #include "extensions/common/manifest_constants.h"
108 #include "testing/gtest/include/gtest/gtest.h"
109 #include "ui/aura/client/window_parenting_client.h"
110 #include "ui/aura/window.h"
111 #include "ui/base/models/menu_model.h"
112 #include "ui/display/display.h"
113 #include "ui/display/display_switches.h"
114 #include "ui/display/screen.h"
115 #include "ui/events/base_event_utils.h"
116 #include "ui/events/event_constants.h"
117 #include "ui/views/widget/widget.h"
118
119 using base::ASCIIToUTF16;
120 using extensions::Extension;
121 using extensions::Manifest;
122 using extensions::UnloadedExtensionInfo;
123 using arc::mojom::OrientationLock;
124
125 namespace {
126 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
127 const char* gmail_url = "https://mail.google.com/mail/u";
128 const char* kGmailLaunchURL = "https://mail.google.com/mail/ca";
129
130 // An extension prefix.
131 const char kCrxAppPrefix[] = "_crx_";
132
133 // Dummy app id is used to put at least one pin record to prevent initializing
134 // pin model with default apps that can affect some tests.
135 const char kDummyAppId[] = "dummyappid_dummyappid_dummyappid";
136
137 // ShelfModelObserver implementation that tracks what messages are invoked.
138 class TestShelfModelObserver : public ash::ShelfModelObserver {
139 public:
140 TestShelfModelObserver() {}
141 ~TestShelfModelObserver() override {}
142
143 // Overridden from ash::ShelfModelObserver:
144 void ShelfItemAdded(int index) override {
145 ++added_;
146 last_index_ = index;
147 }
148
149 void ShelfItemRemoved(int index, const ash::ShelfItem& old_item) override {
150 ++removed_;
151 last_index_ = index;
152 }
153
154 void ShelfItemChanged(int index, const ash::ShelfItem& old_item) override {
155 ++changed_;
156 last_index_ = index;
157 }
158
159 void ShelfItemMoved(int start_index, int target_index) override {
160 last_index_ = target_index;
161 }
162
163 void clear_counts() {
164 added_ = 0;
165 removed_ = 0;
166 changed_ = 0;
167 last_index_ = 0;
168 }
169
170 int added() const { return added_; }
171 int removed() const { return removed_; }
172 int changed() const { return changed_; }
173 int last_index() const { return last_index_; }
174
175 private:
176 int added_ = 0;
177 int removed_ = 0;
178 int changed_ = 0;
179 int last_index_ = 0;
180
181 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver);
182 };
183
184 // Test implementation of AppIconLoader.
185 class TestAppIconLoaderImpl : public AppIconLoader {
186 public:
187 TestAppIconLoaderImpl() = default;
188 ~TestAppIconLoaderImpl() override = default;
189
190 void AddSupportedApp(const std::string& id) { supported_apps_.insert(id); }
191
192 // AppIconLoader implementation:
193 bool CanLoadImageForApp(const std::string& id) override {
194 return supported_apps_.find(id) != supported_apps_.end();
195 }
196 void FetchImage(const std::string& id) override { ++fetch_count_; }
197 void ClearImage(const std::string& id) override { ++clear_count_; }
198 void UpdateImage(const std::string& id) override {}
199
200 int fetch_count() const { return fetch_count_; }
201 int clear_count() const { return clear_count_; }
202
203 private:
204 int fetch_count_ = 0;
205 int clear_count_ = 0;
206 std::set<std::string> supported_apps_;
207
208 DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl);
209 };
210
211 // Test implementation of LauncherControllerHelper.
212 class TestLauncherControllerHelper : public LauncherControllerHelper {
213 public:
214 TestLauncherControllerHelper() : LauncherControllerHelper(nullptr) {}
215 explicit TestLauncherControllerHelper(Profile* profile)
216 : LauncherControllerHelper(profile) {}
217 ~TestLauncherControllerHelper() override {}
218
219 // Sets the id for the specified tab.
220 void SetAppID(content::WebContents* tab, const std::string& id) {
221 tab_id_map_[tab] = id;
222 }
223
224 // Returns true if there is an id registered for |tab|.
225 bool HasAppID(content::WebContents* tab) const {
226 return tab_id_map_.find(tab) != tab_id_map_.end();
227 }
228
229 // LauncherControllerHelper:
230 std::string GetAppID(content::WebContents* tab) override {
231 return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] :
232 std::string();
233 }
234
235 bool IsValidIDForCurrentUser(const std::string& id) const override {
236 for (TabToStringMap::const_iterator i = tab_id_map_.begin();
237 i != tab_id_map_.end(); ++i) {
238 if (i->second == id)
239 return true;
240 }
241 return false;
242 }
243
244 ArcAppListPrefs* GetArcAppListPrefs() const override { return nullptr; }
245
246 private:
247 typedef std::map<content::WebContents*, std::string> TabToStringMap;
248
249 TabToStringMap tab_id_map_;
250
251 DISALLOW_COPY_AND_ASSIGN(TestLauncherControllerHelper);
252 };
253
254 // Test implementation of a V2 app launcher item controller.
255 class TestV2AppLauncherItemController : public ash::ShelfItemDelegate {
256 public:
257 explicit TestV2AppLauncherItemController(const std::string& app_id)
258 : ash::ShelfItemDelegate(ash::AppLaunchId(app_id)) {}
259
260 ~TestV2AppLauncherItemController() override {}
261
262 // Override for ash::ShelfItemDelegate:
263 void ItemSelected(std::unique_ptr<ui::Event> event,
264 int64_t display_id,
265 ash::ShelfLaunchSource source,
266 const ItemSelectedCallback& callback) override {
267 callback.Run(ash::SHELF_ACTION_WINDOW_ACTIVATED, base::nullopt);
268 }
269 void ExecuteCommand(uint32_t command_id, int32_t event_flags) override {}
270 void Close() override {}
271
272 private:
273 DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController);
274 };
275
276 // A test ShelfController implementation that tracks alignment and auto-hide.
277 class TestShelfController : public ash::mojom::ShelfController {
278 public:
279 TestShelfController() : binding_(this) {}
280 ~TestShelfController() override {}
281
282 ash::ShelfAlignment alignment() const { return alignment_; }
283 ash::ShelfAutoHideBehavior auto_hide() const { return auto_hide_; }
284
285 size_t alignment_change_count() const { return alignment_change_count_; }
286 size_t auto_hide_change_count() const { return auto_hide_change_count_; }
287
288 ash::mojom::ShelfControllerPtr CreateInterfacePtrAndBind() {
289 return binding_.CreateInterfacePtrAndBind();
290 }
291
292 // ash::mojom::ShelfController:
293 void AddObserver(
294 ash::mojom::ShelfObserverAssociatedPtrInfo observer) override {
295 observer_.Bind(std::move(observer));
296 }
297 void SetAlignment(ash::ShelfAlignment alignment,
298 int64_t display_id) override {
299 alignment_change_count_++;
300 alignment_ = alignment;
301 observer_->OnAlignmentChanged(alignment_, display_id);
302 }
303 void SetAutoHideBehavior(ash::ShelfAutoHideBehavior auto_hide,
304 int64_t display_id) override {
305 auto_hide_change_count_++;
306 auto_hide_ = auto_hide;
307 observer_->OnAutoHideBehaviorChanged(auto_hide_, display_id);
308 }
309 void PinItem(
310 const ash::ShelfItem& item,
311 ash::mojom::ShelfItemDelegateAssociatedPtrInfo delegate) override {}
312 void UnpinItem(const std::string& app_id) override {}
313 void SetItemImage(const std::string& app_id, const SkBitmap& image) override {
314 }
315
316 private:
317 ash::ShelfAlignment alignment_ = ash::SHELF_ALIGNMENT_BOTTOM_LOCKED;
318 ash::ShelfAutoHideBehavior auto_hide_ = ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
319
320 size_t alignment_change_count_ = 0;
321 size_t auto_hide_change_count_ = 0;
322
323 ash::mojom::ShelfObserverAssociatedPtr observer_;
324 mojo::Binding<ash::mojom::ShelfController> binding_;
325
326 DISALLOW_COPY_AND_ASSIGN(TestShelfController);
327 };
328
329 // A callback that does nothing after shelf item selection handling.
330 void NoopCallback(ash::ShelfAction action, base::Optional<ash::MenuItemList>) {}
331
332 // Simulates selection of the shelf item.
333 void SelectItem(ash::ShelfItemDelegate* delegate) {
334 std::unique_ptr<ui::Event> event = base::MakeUnique<ui::MouseEvent>(
335 ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
336 ui::EF_NONE, 0);
337 delegate->ItemSelected(std::move(event), display::kInvalidDisplayId,
338 ash::LAUNCH_FROM_UNKNOWN, base::Bind(&NoopCallback));
339 }
340
341 } // namespace
342
343 // A test ChromeLauncherControllerImpl subclass that uses TestShelfController.
344 class TestChromeLauncherControllerImpl : public ChromeLauncherControllerImpl {
345 public:
346 TestChromeLauncherControllerImpl(Profile* profile, ash::ShelfModel* model)
347 : ChromeLauncherControllerImpl(profile, model) {}
348
349 // ChromeLauncherControllerImpl:
350 using ChromeLauncherControllerImpl::ReleaseProfile;
351 bool ConnectToShelfController() override {
352 // Set the shelf controller pointer to a test instance; this is run in init.
353 if (!shelf_controller_.is_bound())
354 shelf_controller_ = test_shelf_controller_.CreateInterfacePtrAndBind();
355 return true;
356 }
357
358 TestShelfController* test_shelf_controller() {
359 return &test_shelf_controller_;
360 }
361
362 private:
363 TestShelfController test_shelf_controller_;
364
365 DISALLOW_COPY_AND_ASSIGN(TestChromeLauncherControllerImpl);
366 };
367
368 // A shell delegate that owns a ChromeLauncherController, like production.
369 // TODO(msw): Refine ChromeLauncherControllerImpl lifetime management.
370 // TODO(msw): Avoid relying on TestShellDelegate's ShelfInitializer.
371 class ChromeLauncherTestShellDelegate : public ash::test::TestShellDelegate {
372 public:
373 ChromeLauncherTestShellDelegate() {}
374
375 // Create a ChromeLauncherControllerImpl instance.
376 ChromeLauncherControllerImpl* CreateLauncherController(Profile* profile) {
377 launcher_controller_ = base::MakeUnique<ChromeLauncherControllerImpl>(
378 profile, ash::Shell::Get()->shelf_model());
379 return launcher_controller_.get();
380 }
381
382 // Create a TestChromeLauncherControllerImpl instance.
383 TestChromeLauncherControllerImpl* CreateTestLauncherController(
384 Profile* profile) {
385 auto controller = base::MakeUnique<TestChromeLauncherControllerImpl>(
386 profile, ash::Shell::Get()->shelf_model());
387 TestChromeLauncherControllerImpl* controller_weak = controller.get();
388 launcher_controller_ = std::move(controller);
389 launcher_controller_->Init();
390 return controller_weak;
391 }
392
393 // ash::test::TestShellDelegate:
394 void ShelfShutdown() override { launcher_controller_.reset(); }
395
396 private:
397 std::unique_ptr<ChromeLauncherControllerImpl> launcher_controller_;
398
399 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherTestShellDelegate);
400 };
401
402 class ChromeLauncherControllerImplTest : public BrowserWithTestWindowTest {
403 protected:
404 ChromeLauncherControllerImplTest()
405 : BrowserWithTestWindowTest(Browser::TYPE_TABBED, false) {}
406
407 ~ChromeLauncherControllerImplTest() override {}
408
409 void SetUp() override {
410 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
411 command_line->AppendSwitch(switches::kUseFirstDisplayAsInternal);
412
413 app_list::AppListSyncableServiceFactory::SetUseInTesting();
414
415 shell_delegate_ = new ChromeLauncherTestShellDelegate();
416 ash_test_helper()->set_test_shell_delegate(shell_delegate_);
417
418 BrowserWithTestWindowTest::SetUp();
419
420 if (!profile_manager_) {
421 profile_manager_.reset(
422 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
423 ASSERT_TRUE(profile_manager_->SetUp());
424 }
425
426 model_ = ash::Shell::Get()->shelf_controller()->model();
427 model_observer_.reset(new TestShelfModelObserver);
428 model_->AddObserver(model_observer_.get());
429
430 base::DictionaryValue manifest;
431 manifest.SetString(extensions::manifest_keys::kName,
432 "launcher controller test extension");
433 manifest.SetString(extensions::manifest_keys::kVersion, "1");
434 manifest.SetString(extensions::manifest_keys::kDescription,
435 "for testing pinned apps");
436
437 base::DictionaryValue manifest_platform_app;
438 manifest_platform_app.SetString(extensions::manifest_keys::kName,
439 "launcher controller test platform app");
440 manifest_platform_app.SetString(extensions::manifest_keys::kVersion, "1");
441 manifest_platform_app.SetString(extensions::manifest_keys::kDescription,
442 "for testing pinned platform apps");
443 manifest_platform_app.SetString(extensions::manifest_keys::kApp, "true");
444 manifest_platform_app.Set(extensions::manifest_keys::kPlatformAppBackground,
445 base::MakeUnique<base::DictionaryValue>());
446 auto scripts = base::MakeUnique<base::ListValue>();
447 scripts->AppendString("main.js");
448 manifest_platform_app.Set(
449 extensions::manifest_keys::kPlatformAppBackgroundScripts,
450 std::move(scripts));
451
452 extensions::TestExtensionSystem* extension_system(
453 static_cast<extensions::TestExtensionSystem*>(
454 extensions::ExtensionSystem::Get(profile())));
455 extension_service_ = extension_system->CreateExtensionService(
456 base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
457 extension_service_->Init();
458
459 if (auto_start_arc_test_)
460 arc_test_.SetUp(profile());
461
462 // Wait until |extension_system| is signaled as started.
463 base::RunLoop run_loop;
464 extension_system->ready().Post(FROM_HERE, run_loop.QuitClosure());
465 run_loop.Run();
466
467 app_service_ =
468 app_list::AppListSyncableServiceFactory::GetForProfile(profile());
469 StartAppSyncService(syncer::SyncDataList());
470
471 std::string error;
472 extension_chrome_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
473 manifest, Extension::NO_FLAGS,
474 extension_misc::kChromeAppId, &error);
475 extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
476 manifest, Extension::NO_FLAGS,
477 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &error);
478 extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
479 manifest, Extension::NO_FLAGS,
480 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", &error);
481 // Fake gmail extension.
482 base::DictionaryValue manifest_gmail;
483 manifest_gmail.SetString(extensions::manifest_keys::kName,
484 "Gmail launcher controller test extension");
485 manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1");
486 manifest_gmail.SetString(extensions::manifest_keys::kDescription,
487 "for testing pinned Gmail");
488 manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL,
489 kGmailLaunchURL);
490 auto list = base::MakeUnique<base::ListValue>();
491 list->AppendString("*://mail.google.com/mail/ca");
492 manifest_gmail.Set(extensions::manifest_keys::kWebURLs, std::move(list));
493
494 extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
495 manifest_gmail, Extension::NO_FLAGS,
496 extension_misc::kGmailAppId, &error);
497
498 // Fake google docs extension.
499 extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
500 manifest, Extension::NO_FLAGS,
501 extension_misc::kGoogleDocAppId, &error);
502 extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
503 manifest, Extension::NO_FLAGS,
504 "cccccccccccccccccccccccccccccccc", &error);
505 extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
506 manifest, Extension::NO_FLAGS,
507 "dddddddddddddddddddddddddddddddd", &error);
508 extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
509 manifest, Extension::NO_FLAGS,
510 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", &error);
511 extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
512 manifest, Extension::NO_FLAGS,
513 "ffffffffffffffffffffffffffffffff", &error);
514 extension_platform_app_ = Extension::Create(
515 base::FilePath(), Manifest::UNPACKED, manifest_platform_app,
516 Extension::NO_FLAGS, "gggggggggggggggggggggggggggggggg", &error);
517 arc_support_host_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
518 manifest, Extension::NO_FLAGS,
519 ArcSupportHost::kHostAppId, &error);
520 extension_service_->AddExtension(extension_chrome_.get());
521 }
522
523 // Creates a running platform V2 app (not pinned) of type |app_id|.
524 virtual void CreateRunningV2App(const std::string& app_id) {
525 DCHECK(!test_controller_);
526 // Change the created launcher controller into a V2 app controller.
527 std::unique_ptr<TestV2AppLauncherItemController> controller =
528 base::MakeUnique<TestV2AppLauncherItemController>(app_id);
529 test_controller_ = controller.get();
530 ash::ShelfID id = launcher_controller_->InsertAppLauncherItem(
531 std::move(controller), ash::STATUS_RUNNING, model_->item_count(),
532 ash::TYPE_APP);
533 DCHECK(launcher_controller_->IsPlatformApp(id));
534 }
535
536 // Sets the stage for a multi user test.
537 virtual void SetUpMultiUserScenario(syncer::SyncChangeList* user_a,
538 syncer::SyncChangeList* user_b) {
539 InitLauncherController();
540 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
541
542 // Set an empty pinned pref to begin with.
543 syncer::SyncChangeList sync_list;
544 InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
545 SendPinChanges(sync_list, true);
546 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
547
548 // Assume all applications have been added already.
549 extension_service_->AddExtension(extension1_.get());
550 extension_service_->AddExtension(extension2_.get());
551 extension_service_->AddExtension(extension3_.get());
552 extension_service_->AddExtension(extension4_.get());
553 extension_service_->AddExtension(extension5_.get());
554 extension_service_->AddExtension(extension6_.get());
555 extension_service_->AddExtension(extension7_.get());
556 extension_service_->AddExtension(extension8_.get());
557 extension_service_->AddExtension(extension_platform_app_.get());
558 // There should be nothing in the list by now.
559 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
560
561 // Set user a preferences.
562 InsertAddPinChange(user_a, 0, extension1_->id());
563 InsertAddPinChange(user_a, 1, extension2_->id());
564 InsertAddPinChange(user_a, 2, extension3_->id());
565 InsertAddPinChange(user_a, 3, extension_platform_app_->id());
566 InsertAddPinChange(user_a, 4, extension4_->id());
567 InsertAddPinChange(user_a, 5, extension5_->id());
568 InsertAddPinChange(user_a, 6, extension_misc::kChromeAppId);
569
570 // Set user b preferences.
571 InsertAddPinChange(user_b, 0, extension6_->id());
572 InsertAddPinChange(user_b, 1, extension7_->id());
573 InsertAddPinChange(user_b, 2, extension8_->id());
574 InsertAddPinChange(user_b, 3, extension_misc::kChromeAppId);
575 }
576
577 void TearDown() override {
578 arc_test_.TearDown();
579 model_->RemoveObserver(model_observer_.get());
580 model_observer_.reset();
581 launcher_controller_ = nullptr;
582 BrowserWithTestWindowTest::TearDown();
583 }
584
585 BrowserWindow* CreateBrowserWindow() override {
586 return CreateTestBrowserWindowAura();
587 }
588
589 std::unique_ptr<Browser> CreateBrowserWithTestWindowForProfile(
590 Profile* profile) {
591 TestBrowserWindow* browser_window = CreateTestBrowserWindowAura();
592 new TestBrowserWindowOwner(browser_window);
593 return base::WrapUnique(
594 CreateBrowser(profile, Browser::TYPE_TABBED, false, browser_window));
595 }
596
597 void AddAppListLauncherItem() {
598 ash::ShelfItem app_list;
599 app_list.type = ash::TYPE_APP_LIST;
600 model_->Add(app_list);
601 }
602
603 // Create a launcher controller instance, owned by the test shell delegate.
604 // Returns a pointer to the uninitialized controller.
605 ChromeLauncherControllerImpl* CreateLauncherController() {
606 launcher_controller_ = shell_delegate_->CreateLauncherController(profile());
607 return launcher_controller_;
608 }
609
610 // Create and initialize the controller, owned by the test shell delegate.
611 void InitLauncherController() { CreateLauncherController()->Init(); }
612
613 // Create and initialize the controller; create a tab and show the browser.
614 void InitLauncherControllerWithBrowser() {
615 InitLauncherController();
616 chrome::NewTab(browser());
617 browser()->window()->Show();
618 }
619
620 // Destroy the launcher controller instance and clear the local pointer.
621 void ResetLauncherController() {
622 launcher_controller_ = nullptr;
623 shell_delegate_->ShelfShutdown();
624 }
625
626 // Destroy and recreate the controller; clear and reinitialize the ShelfModel.
627 // Returns a pointer to the uninitialized controller, owned by shell delegate.
628 // TODO(msw): This does not accurately represent ChromeLauncherControllerImpl
629 // lifetime or usage in production, and does not accurately simulate restarts.
630 ChromeLauncherControllerImpl* RecreateLauncherController() {
631 // Destroy any existing controller first; only one may exist at a time.
632 ResetLauncherController();
633 while (model_->item_count() > 0)
634 model_->RemoveItemAt(0);
635 AddAppListLauncherItem();
636 return CreateLauncherController();
637 }
638
639 void StartAppSyncService(const syncer::SyncDataList& init_sync_list) {
640 app_service_->MergeDataAndStartSyncing(
641 syncer::APP_LIST, init_sync_list,
642 base::MakeUnique<syncer::FakeSyncChangeProcessor>(),
643 base::MakeUnique<syncer::SyncErrorFactoryMock>());
644 EXPECT_EQ(init_sync_list.size(), app_service_->sync_items().size());
645 }
646
647 void StopAppSyncService() { app_service_->StopSyncing(syncer::APP_LIST); }
648
649 sync_preferences::PrefModelAssociator* GetPrefSyncService() {
650 sync_preferences::PrefServiceSyncable* pref_sync =
651 profile()->GetTestingPrefService();
652 sync_preferences::PrefModelAssociator* pref_sync_service =
653 reinterpret_cast<sync_preferences::PrefModelAssociator*>(
654 pref_sync->GetSyncableService(syncer::PREFERENCES));
655 return pref_sync_service;
656 }
657
658 void StartPrefSyncService(const syncer::SyncDataList& init_sync_list) {
659 syncer::SyncMergeResult r = GetPrefSyncService()->MergeDataAndStartSyncing(
660 syncer::PREFERENCES, init_sync_list,
661 base::MakeUnique<syncer::FakeSyncChangeProcessor>(),
662 base::MakeUnique<syncer::SyncErrorFactoryMock>());
663 EXPECT_FALSE(r.error().IsSet());
664 }
665
666 void StartPrefSyncServiceForPins(const base::ListValue& init_value) {
667 syncer::SyncDataList init_sync_list;
668 std::string serialized;
669 JSONStringValueSerializer json(&serialized);
670 json.Serialize(init_value);
671 sync_pb::EntitySpecifics one;
672 sync_pb::PreferenceSpecifics* pref_one = one.mutable_preference();
673 pref_one->set_name(prefs::kPinnedLauncherApps);
674 pref_one->set_value(serialized);
675 init_sync_list.push_back(syncer::SyncData::CreateRemoteData(
676 1, one, base::Time(), syncer::AttachmentIdList(),
677 syncer::AttachmentServiceProxyForTest::Create()));
678 StartPrefSyncService(init_sync_list);
679 }
680
681 void StopPrefSyncService() {
682 GetPrefSyncService()->StopSyncing(syncer::PREFERENCES);
683 }
684
685 void SetAppIconLoader(std::unique_ptr<AppIconLoader> loader) {
686 std::vector<std::unique_ptr<AppIconLoader>> loaders;
687 loaders.push_back(std::move(loader));
688 launcher_controller_->SetAppIconLoadersForTest(loaders);
689 }
690
691 void SetAppIconLoaders(std::unique_ptr<AppIconLoader> loader1,
692 std::unique_ptr<AppIconLoader> loader2) {
693 std::vector<std::unique_ptr<AppIconLoader>> loaders;
694 loaders.push_back(std::move(loader1));
695 loaders.push_back(std::move(loader2));
696 launcher_controller_->SetAppIconLoadersForTest(loaders);
697 }
698
699 void SetLauncherControllerHelper(LauncherControllerHelper* helper) {
700 launcher_controller_->SetLauncherControllerHelperForTest(
701 base::WrapUnique<LauncherControllerHelper>(helper));
702 }
703
704 void InsertPrefValue(base::ListValue* pref_value,
705 int index,
706 const std::string& extension_id) {
707 auto entry = base::MakeUnique<base::DictionaryValue>();
708 entry->SetString(ash::launcher::kPinnedAppsPrefAppIDPath, extension_id);
709 pref_value->Insert(index, std::move(entry));
710 }
711
712 void InsertRemoveAllPinsChange(syncer::SyncChangeList* list) {
713 for (const auto& sync_peer : app_service_->sync_items()) {
714 sync_pb::EntitySpecifics specifics;
715 sync_pb::AppListSpecifics* app_list_specifics =
716 specifics.mutable_app_list();
717 app_list_specifics->set_item_id(sync_peer.first);
718 app_list_specifics->set_item_type(sync_pb::AppListSpecifics::TYPE_APP);
719 syncer::SyncData sync_data =
720 syncer::SyncData::CreateLocalData(sync_peer.first, "Test", specifics);
721 list->push_back(syncer::SyncChange(
722 FROM_HERE, syncer::SyncChange::ACTION_DELETE, sync_data));
723 }
724 }
725
726 syncer::StringOrdinal GeneratePinPosition(int position) {
727 syncer::StringOrdinal ordinal_position =
728 syncer::StringOrdinal::CreateInitialOrdinal();
729 for (int i = 0; i < position; ++i)
730 ordinal_position = ordinal_position.CreateAfter();
731 return ordinal_position;
732 }
733
734 void InsertPinChange(syncer::SyncChangeList* list,
735 int position,
736 bool add_pin_change,
737 const std::string& app_id,
738 syncer::SyncChange::SyncChangeType type) {
739 sync_pb::EntitySpecifics specifics;
740 sync_pb::AppListSpecifics* app_list_specifics =
741 specifics.mutable_app_list();
742 app_list_specifics->set_item_id(app_id);
743 app_list_specifics->set_item_type(sync_pb::AppListSpecifics::TYPE_APP);
744 if (add_pin_change) {
745 if (position >= 0) {
746 app_list_specifics->set_item_pin_ordinal(
747 GeneratePinPosition(position).ToInternalValue());
748 } else {
749 app_list_specifics->set_item_pin_ordinal(std::string());
750 }
751 }
752 syncer::SyncData sync_data =
753 syncer::SyncData::CreateLocalData(app_id, "Test", specifics);
754 list->push_back(syncer::SyncChange(FROM_HERE, type, sync_data));
755 }
756
757 void InsertAddPinChange(syncer::SyncChangeList* list,
758 int position,
759 const std::string& app_id) {
760 InsertPinChange(list, position, true, app_id,
761 syncer::SyncChange::ACTION_ADD);
762 }
763
764 void InsertUpdatePinChange(syncer::SyncChangeList* list,
765 int position,
766 const std::string& app_id) {
767 InsertPinChange(list, position, true, app_id,
768 syncer::SyncChange::ACTION_UPDATE);
769 }
770
771 void InsertRemovePinChange(syncer::SyncChangeList* list,
772 const std::string& app_id) {
773 InsertPinChange(list, -1, true, app_id, syncer::SyncChange::ACTION_UPDATE);
774 }
775
776 void InsertLegacyPinChange(syncer::SyncChangeList* list,
777 const std::string& app_id) {
778 InsertPinChange(list, -1, false, app_id, syncer::SyncChange::ACTION_UPDATE);
779 }
780
781 void ResetPinModel() {
782 syncer::SyncChangeList sync_list;
783 InsertRemoveAllPinsChange(&sync_list);
784 InsertAddPinChange(&sync_list, 0, kDummyAppId);
785 app_service_->ProcessSyncChanges(FROM_HERE, sync_list);
786 }
787
788 void SendPinChanges(const syncer::SyncChangeList& sync_list,
789 bool reset_pin_model) {
790 if (!reset_pin_model) {
791 app_service_->ProcessSyncChanges(FROM_HERE, sync_list);
792 } else {
793 syncer::SyncChangeList combined_sync_list;
794 InsertRemoveAllPinsChange(&combined_sync_list);
795 combined_sync_list.insert(combined_sync_list.end(), sync_list.begin(),
796 sync_list.end());
797 app_service_->ProcessSyncChanges(FROM_HERE, combined_sync_list);
798 }
799 }
800
801 // Set the index at which the chrome icon should be.
802 void SetShelfChromeIconIndex(int index) {
803 DCHECK(
804 app_service_->GetPinPosition(extension_misc::kChromeAppId).IsValid());
805 syncer::StringOrdinal chrome_position;
806 chrome_position = index == 0 ? GeneratePinPosition(0).CreateBefore()
807 : GeneratePinPosition(index - 1).CreateBetween(
808 GeneratePinPosition(index));
809
810 syncer::SyncChangeList sync_list;
811 sync_pb::EntitySpecifics specifics;
812 sync_pb::AppListSpecifics* app_list_specifics =
813 specifics.mutable_app_list();
814 app_list_specifics->set_item_id(extension_misc::kChromeAppId);
815 app_list_specifics->set_item_type(sync_pb::AppListSpecifics::TYPE_APP);
816 app_list_specifics->set_item_pin_ordinal(chrome_position.ToInternalValue());
817 syncer::SyncData sync_data = syncer::SyncData::CreateLocalData(
818 extension_misc::kChromeAppId, "Test", specifics);
819 sync_list.push_back(syncer::SyncChange(
820 FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
821 app_service_->ProcessSyncChanges(FROM_HERE, sync_list);
822 }
823
824 // Gets the IDs of the currently pinned app items.
825 void GetPinnedAppIds(ChromeLauncherControllerImpl* controller,
826 std::vector<std::string>* app_ids) {
827 app_ids->clear();
828 for (const auto& item : model_->items()) {
829 if (item.type == ash::TYPE_PINNED_APP)
830 app_ids->push_back(item.app_launch_id.app_id());
831 }
832 }
833
834 // Get the setup of the currently shown launcher items in one string.
835 // Each pinned element will start with a big letter, each running but not
836 // pinned V1 app will start with a small letter and each running but not
837 // pinned V2 app will start with a '*' + small letter.
838 std::string GetPinnedAppStatus() {
839 std::string result;
840 for (int i = 0; i < model_->item_count(); i++) {
841 if (!result.empty())
842 result.append(", ");
843 switch (model_->items()[i].type) {
844 case ash::TYPE_APP: {
845 if (launcher_controller_->IsPlatformApp(model_->items()[i].id))
846 result += "*";
847 const std::string& app =
848 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id);
849 EXPECT_FALSE(launcher_controller_->IsAppPinned(app));
850 if (app == extension1_->id()) {
851 result += "app1";
852 } else if (app == extension2_->id()) {
853 result += "app2";
854 } else if (app == extension3_->id()) {
855 result += "app3";
856 } else if (app == extension4_->id()) {
857 result += "app4";
858 } else if (app == extension5_->id()) {
859 result += "app5";
860 } else if (app == extension6_->id()) {
861 result += "app6";
862 } else if (app == extension7_->id()) {
863 result += "app7";
864 } else if (app == extension8_->id()) {
865 result += "app8";
866 } else if (app == extension_platform_app_->id()) {
867 result += "platform_app";
868 } else {
869 result += "unknown";
870 }
871 break;
872 }
873 case ash::TYPE_PINNED_APP: {
874 if (launcher_controller_->IsPlatformApp(model_->items()[i].id))
875 result += "*";
876 const std::string& app =
877 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id);
878 EXPECT_TRUE(launcher_controller_->IsAppPinned(app));
879 if (app == extension1_->id()) {
880 result += "App1";
881 } else if (app == extension2_->id()) {
882 result += "App2";
883 } else if (app == extension3_->id()) {
884 result += "App3";
885 } else if (app == extension4_->id()) {
886 result += "App4";
887 } else if (app == extension5_->id()) {
888 result += "App5";
889 } else if (app == extension6_->id()) {
890 result += "App6";
891 } else if (app == extension7_->id()) {
892 result += "App7";
893 } else if (app == extension8_->id()) {
894 result += "App8";
895 } else if (app == extension_platform_app_->id()) {
896 result += "Platform_App";
897 } else if (app == arc_support_host_->id()) {
898 result += "Play Store";
899 } else {
900 bool arc_app_found = false;
901 for (const auto& arc_app : arc_test_.fake_apps()) {
902 if (app == ArcAppTest::GetAppId(arc_app)) {
903 result += arc_app.name;
904 arc_app_found = true;
905 break;
906 }
907 }
908 if (!arc_app_found)
909 result += "unknown";
910 }
911 break;
912 }
913 case ash::TYPE_BROWSER_SHORTCUT:
914 result += "Chrome";
915 break;
916 case ash::TYPE_APP_LIST:
917 result += "AppList";
918 break;
919 default:
920 result += "Unknown";
921 break;
922 }
923 }
924 return result;
925 }
926
927 // Remember the order of unpinned but running applications for the current
928 // user.
929 void RememberUnpinnedRunningApplicationOrder() {
930 launcher_controller_->RememberUnpinnedRunningApplicationOrder();
931 }
932
933 // Restore the order of running but unpinned applications for a given user.
934 void RestoreUnpinnedRunningApplicationOrder(const AccountId& account_id) {
935 launcher_controller_->RestoreUnpinnedRunningApplicationOrder(
936 account_id.GetUserEmail());
937 }
938
939 void SendListOfArcApps() {
940 arc_test_.app_instance()->RefreshAppList();
941 arc_test_.app_instance()->SendRefreshAppList(arc_test_.fake_apps());
942 }
943
944 void SendListOfArcShortcuts() {
945 arc_test_.app_instance()->SendInstallShortcuts(arc_test_.fake_shortcuts());
946 }
947
948 void UninstallArcApps() {
949 arc_test_.app_instance()->RefreshAppList();
950 arc_test_.app_instance()->SendRefreshAppList(
951 std::vector<arc::mojom::AppInfo>());
952 }
953
954 // TODO(victorhsieh): Add test coverage for when ARC is started regardless
955 // Play Store opt-in status, and the followed opt-in and opt-out.
956 void EnablePlayStore(bool enabled) {
957 arc::SetArcPlayStoreEnabledForProfile(profile(), enabled);
958 base::RunLoop().RunUntilIdle();
959 }
960
961 void EnableTabletMode(bool enable) {
962 ash::MaximizeModeController* controller =
963 ash::Shell::Get()->maximize_mode_controller();
964 controller->EnableMaximizeModeWindowManager(enable);
965 }
966
967 void ValidateArcState(bool arc_enabled,
968 bool arc_managed,
969 arc::ArcSessionManager::State state,
970 const std::string& pin_status) {
971 EXPECT_EQ(arc_enabled, arc::IsArcPlayStoreEnabledForProfile(profile()));
972 EXPECT_EQ(arc_managed,
973 arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile()));
974 EXPECT_EQ(state, arc_test_.arc_session_manager()->state());
975 EXPECT_EQ(pin_status, GetPinnedAppStatus());
976 }
977
978 // Creates app window and set optional ARC application id.
979 views::Widget* CreateArcWindow(const std::string& window_app_id) {
980 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
981 params.bounds = gfx::Rect(5, 5, 20, 20);
982 params.context = GetContext();
983 views::Widget* widget = new views::Widget();
984 widget->Init(params);
985 // Set ARC id before showing the window to be recognized in
986 // ArcAppWindowLauncherController.
987 exo::ShellSurface::SetApplicationId(widget->GetNativeWindow(),
988 window_app_id);
989 widget->Show();
990 widget->Activate();
991 return widget;
992 }
993
994 arc::mojom::AppInfo CreateAppInfo(const std::string& name,
995 const std::string& activity,
996 const std::string& package_name,
997 OrientationLock lock) {
998 arc::mojom::AppInfo appinfo;
999 appinfo.name = name;
1000 appinfo.package_name = package_name;
1001 appinfo.activity = activity;
1002 appinfo.orientation_lock = lock;
1003 return appinfo;
1004 }
1005
1006 std::string AddArcAppAndShortcut(const arc::mojom::AppInfo& app_info) {
1007 ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
1008 // Adding app to the prefs, and check that the app is accessible by id.
1009 prefs->AddAppAndShortcut(
1010 true /* app_ready */, app_info.name, app_info.package_name,
1011 app_info.activity, std::string() /* intent_uri */,
1012 std::string() /* icon_resource_id */, false /* sticky */,
1013 true /* notifications_enabled */, false /* shortcut */,
1014 true /* launchable */, app_info.orientation_lock);
1015 const std::string app_id =
1016 ArcAppListPrefs::GetAppId(app_info.package_name, app_info.activity);
1017 EXPECT_TRUE(prefs->GetApp(app_id));
1018 return app_id;
1019 }
1020
1021 void NotifyOnTaskCreated(const arc::mojom::AppInfo& appinfo,
1022 int32_t task_id) {
1023 ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
1024 prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity,
1025 appinfo.name, std::string());
1026 }
1027
1028 void NotifyOnTaskOrientationLockRequested(int32_t task_id,
1029 OrientationLock lock) {
1030 ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
1031 prefs->OnTaskOrientationLockRequested(task_id, lock);
1032 }
1033
1034 // Needed for extension service & friends to work.
1035 scoped_refptr<Extension> extension_chrome_;
1036 scoped_refptr<Extension> extension1_;
1037 scoped_refptr<Extension> extension2_;
1038 scoped_refptr<Extension> extension3_;
1039 scoped_refptr<Extension> extension4_;
1040 scoped_refptr<Extension> extension5_;
1041 scoped_refptr<Extension> extension6_;
1042 scoped_refptr<Extension> extension7_;
1043 scoped_refptr<Extension> extension8_;
1044 scoped_refptr<Extension> extension_platform_app_;
1045 scoped_refptr<Extension> arc_support_host_;
1046
1047 ArcAppTest arc_test_;
1048 bool auto_start_arc_test_ = false;
1049 ChromeLauncherControllerImpl* launcher_controller_ = nullptr;
1050 ChromeLauncherTestShellDelegate* shell_delegate_ = nullptr;
1051 std::unique_ptr<TestShelfModelObserver> model_observer_;
1052 ash::ShelfModel* model_ = nullptr;
1053 std::unique_ptr<TestingProfileManager> profile_manager_;
1054
1055 // |item_delegate_manager_| owns |test_controller_|.
1056 ash::ShelfItemDelegate* test_controller_ = nullptr;
1057
1058 ExtensionService* extension_service_ = nullptr;
1059
1060 app_list::AppListSyncableService* app_service_ = nullptr;
1061
1062 private:
1063 TestBrowserWindow* CreateTestBrowserWindowAura() {
1064 std::unique_ptr<aura::Window> window(new aura::Window(nullptr));
1065 window->set_id(0);
1066 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
1067 window->Init(ui::LAYER_TEXTURED);
1068 aura::client::ParentWindowWithContext(window.get(), GetContext(),
1069 gfx::Rect(200, 200));
1070
1071 return new TestBrowserWindowAura(std::move(window));
1072 }
1073
1074 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerImplTest);
1075 };
1076
1077 class ChromeLauncherControllerImplWithArcTest
1078 : public ChromeLauncherControllerImplTest,
1079 public ::testing::WithParamInterface<bool> {
1080 protected:
1081 ChromeLauncherControllerImplWithArcTest() { auto_start_arc_test_ = true; }
1082 ~ChromeLauncherControllerImplWithArcTest() override {}
1083
1084 void SetUp() override {
1085 if (GetParam())
1086 arc::SetArcAlwaysStartForTesting();
1087 ChromeLauncherControllerImplTest::SetUp();
1088 }
1089
1090 private:
1091 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerImplWithArcTest);
1092 };
1093
1094 INSTANTIATE_TEST_CASE_P(,
1095 ChromeLauncherControllerImplWithArcTest,
1096 ::testing::Bool());
1097
1098 // Watches WebContents and blocks until it is destroyed. This is needed for
1099 // the destruction of a V2 application.
1100 class WebContentsDestroyedWatcher : public content::WebContentsObserver {
1101 public:
1102 explicit WebContentsDestroyedWatcher(content::WebContents* web_contents)
1103 : content::WebContentsObserver(web_contents),
1104 message_loop_runner_(new content::MessageLoopRunner) {
1105 EXPECT_TRUE(web_contents != NULL);
1106 }
1107 ~WebContentsDestroyedWatcher() override {}
1108
1109 // Waits until the WebContents is destroyed.
1110 void Wait() {
1111 message_loop_runner_->Run();
1112 }
1113
1114 private:
1115 // Overridden WebContentsObserver methods.
1116 void WebContentsDestroyed() override { message_loop_runner_->Quit(); }
1117
1118 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
1119
1120 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedWatcher);
1121 };
1122
1123 // A V1 windowed application.
1124 class V1App : public TestBrowserWindow {
1125 public:
1126 V1App(Profile* profile, const std::string& app_name) {
1127 Browser::CreateParams params = Browser::CreateParams::CreateForApp(
1128 kCrxAppPrefix + app_name, true /* trusted_source */, gfx::Rect(),
1129 profile, true);
1130 params.window = this;
1131 browser_.reset(new Browser(params));
1132 chrome::AddTabAt(browser_.get(), GURL(), 0, true);
1133 }
1134
1135 ~V1App() override {
1136 // close all tabs. Note that we do not need to destroy the browser itself.
1137 browser_->tab_strip_model()->CloseAllTabs();
1138 }
1139
1140 Browser* browser() { return browser_.get(); }
1141
1142 private:
1143 // The associated browser with this app.
1144 std::unique_ptr<Browser> browser_;
1145
1146 DISALLOW_COPY_AND_ASSIGN(V1App);
1147 };
1148
1149 // A V2 application window created with an |extension| and for a |profile|.
1150 // Upon destruction it will properly close the application; supports panels too.
1151 class V2App {
1152 public:
1153 V2App(Profile* profile,
1154 const extensions::Extension* extension,
1155 extensions::AppWindow::WindowType window_type =
1156 extensions::AppWindow::WINDOW_TYPE_DEFAULT)
1157 : creator_web_contents_(
1158 content::WebContentsTester::CreateTestWebContents(profile,
1159 nullptr)) {
1160 window_ = new extensions::AppWindow(profile, new ChromeAppDelegate(true),
1161 extension);
1162 extensions::AppWindow::CreateParams params;
1163 params.window_type = window_type;
1164 // Note: normally, the creator RFH is the background page of the
1165 // app/extension
1166 // calling chrome.app.window.create. For unit testing purposes, just passing
1167 // in a random RenderFrameHost is Good Enoughâ„¢.
1168 window_->Init(GURL(std::string()),
1169 new extensions::AppWindowContentsImpl(window_),
1170 creator_web_contents_->GetMainFrame(), params);
1171 }
1172
1173 virtual ~V2App() {
1174 WebContentsDestroyedWatcher destroyed_watcher(window_->web_contents());
1175 window_->GetBaseWindow()->Close();
1176 destroyed_watcher.Wait();
1177 }
1178
1179 extensions::AppWindow* window() { return window_; }
1180
1181 private:
1182 std::unique_ptr<content::WebContents> creator_web_contents_;
1183
1184 // The app window which represents the application. Note that the window
1185 // deletes itself asynchronously after window_->GetBaseWindow()->Close() gets
1186 // called.
1187 extensions::AppWindow* window_;
1188
1189 DISALLOW_COPY_AND_ASSIGN(V2App);
1190 };
1191
1192 // The testing framework to test multi profile scenarios.
1193 class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest
1194 : public ChromeLauncherControllerImplTest {
1195 protected:
1196 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest() {}
1197
1198 ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest()
1199 override {}
1200
1201 // Overwrite the Setup function to enable multi profile and needed objects.
1202 void SetUp() override {
1203 profile_manager_.reset(
1204 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
1205
1206 ASSERT_TRUE(profile_manager_->SetUp());
1207
1208 // AvatarMenu and multiple profiles works after user logged in.
1209 profile_manager_->SetLoggedIn(true);
1210
1211 // Initialize the UserManager singleton to a fresh FakeUserManager instance.
1212 user_manager_enabler_.reset(new chromeos::ScopedUserManagerEnabler(
1213 new chromeos::FakeChromeUserManager));
1214
1215 // Initialize the WallpaperManager singleton.
1216 chromeos::WallpaperManager::Initialize();
1217
1218 // Initialize the rest.
1219 ChromeLauncherControllerImplTest::SetUp();
1220 shell_delegate_->set_multi_profiles_enabled(true);
1221 }
1222
1223 void TearDown() override {
1224 ChromeLauncherControllerImplTest::TearDown();
1225 user_manager_enabler_.reset();
1226 for (ProfileToNameMap::iterator it = created_profiles_.begin();
1227 it != created_profiles_.end(); ++it)
1228 profile_manager_->DeleteTestingProfile(it->second);
1229 chromeos::WallpaperManager::Shutdown();
1230
1231 // A Task is leaked if we don't destroy everything, then run the message
1232 // loop.
1233 base::RunLoop().RunUntilIdle();
1234 }
1235
1236 // Creates a profile for a given |user_name|. Note that this class will keep
1237 // the ownership of the created object.
1238 TestingProfile* CreateMultiUserProfile(const std::string& user_name) {
1239 const std::string email_string = user_name + "@example.com";
1240 const AccountId account_id(AccountId::FromUserEmail(email_string));
1241 // Add a user to the fake user manager.
1242 GetFakeUserManager()->AddUser(account_id);
1243
1244 GetFakeUserManager()->LoginUser(account_id);
1245
1246 TestingProfile* profile =
1247 profile_manager()->CreateTestingProfile(account_id.GetUserEmail());
1248 EXPECT_TRUE(profile);
1249
1250 // Remember the profile name so that we can destroy it upon destruction.
1251 created_profiles_[profile] = account_id.GetUserEmail();
1252 if (chrome::MultiUserWindowManager::GetInstance())
1253 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
1254 if (launcher_controller_)
1255 launcher_controller_->AdditionalUserAddedToSession(profile);
1256 return profile;
1257 }
1258
1259 // Switch to another user.
1260 void SwitchActiveUser(const AccountId& account_id) {
1261 GetFakeUserManager()->SwitchActiveUser(account_id);
1262 chrome::MultiUserWindowManagerChromeOS* manager =
1263 static_cast<chrome::MultiUserWindowManagerChromeOS*>(
1264 chrome::MultiUserWindowManager::GetInstance());
1265 manager->SetAnimationSpeedForTest(
1266 chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
1267 manager->ActiveUserChanged(GetFakeUserManager()->FindUser(account_id));
1268 launcher_controller_->browser_status_monitor_for_test()->ActiveUserChanged(
1269 account_id.GetUserEmail());
1270
1271 for (const auto& controller :
1272 launcher_controller_->app_window_controllers_for_test()) {
1273 controller->ActiveUserChanged(account_id.GetUserEmail());
1274 }
1275 }
1276
1277 // Creates a browser with a |profile| and load a tab with a |title| and |url|.
1278 std::unique_ptr<Browser> CreateBrowserAndTabWithProfile(
1279 Profile* profile,
1280 const std::string& title,
1281 const std::string& url) {
1282 std::unique_ptr<Browser> browser(
1283 CreateBrowserWithTestWindowForProfile(profile));
1284 chrome::NewTab(browser.get());
1285
1286 browser->window()->Show();
1287 NavigateAndCommitActiveTabWithTitle(browser.get(), GURL(url),
1288 ASCIIToUTF16(title));
1289 return browser;
1290 }
1291
1292 // Creates a running V1 application.
1293 // Note that with the use of the launcher_controller_helper as done below,
1294 // this is only usable with a single v1 application.
1295 V1App* CreateRunningV1App(Profile* profile,
1296 const std::string& app_name,
1297 const std::string& url) {
1298 V1App* v1_app = new V1App(profile, app_name);
1299 NavigateAndCommitActiveTabWithTitle(v1_app->browser(), GURL(url),
1300 base::string16());
1301 return v1_app;
1302 }
1303
1304 // Override BrowserWithTestWindowTest:
1305 TestingProfile* CreateProfile() override {
1306 return CreateMultiUserProfile("user1");
1307 }
1308 void DestroyProfile(TestingProfile* profile) override {
1309 // Delete the profile through our profile manager.
1310 ProfileToNameMap::iterator it = created_profiles_.find(profile);
1311 DCHECK(it != created_profiles_.end());
1312 profile_manager_->DeleteTestingProfile(it->second);
1313 created_profiles_.erase(it);
1314 }
1315
1316 private:
1317 typedef std::map<Profile*, std::string> ProfileToNameMap;
1318 TestingProfileManager* profile_manager() { return profile_manager_.get(); }
1319
1320 chromeos::FakeChromeUserManager* GetFakeUserManager() {
1321 return static_cast<chromeos::FakeChromeUserManager*>(
1322 user_manager::UserManager::Get());
1323 }
1324
1325 std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
1326
1327 ProfileToNameMap created_profiles_;
1328
1329 DISALLOW_COPY_AND_ASSIGN(
1330 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest);
1331 };
1332
1333 class ChromeLauncherControllerImplMultiProfileWithArcTest
1334 : public MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest , // NOLINT(whitespace/line_length)
1335 public ::testing::WithParamInterface<bool> {
1336 protected:
1337 ChromeLauncherControllerImplMultiProfileWithArcTest() {
1338 auto_start_arc_test_ = true;
1339 }
1340 ~ChromeLauncherControllerImplMultiProfileWithArcTest() override {}
1341
1342 void SetUp() override {
1343 if (GetParam())
1344 arc::SetArcAlwaysStartForTesting();
1345 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest::
1346 SetUp();
1347 }
1348
1349 private:
1350 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerImplMultiProfileWithArcTest);
1351 };
1352
1353 INSTANTIATE_TEST_CASE_P(,
1354 ChromeLauncherControllerImplMultiProfileWithArcTest,
1355 ::testing::Bool());
1356
1357 TEST_F(ChromeLauncherControllerImplTest, DefaultApps) {
1358 InitLauncherController();
1359 // The model should only contain the browser shortcut and app list items.
1360 EXPECT_EQ(2, model_->item_count());
1361 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1362 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1363 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1364
1365 // Installing |extension3_| should add it to the launcher - behind the
1366 // chrome icon.
1367 extension_service_->AddExtension(extension3_.get());
1368 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1369 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1370 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1371 }
1372
1373 TEST_P(ChromeLauncherControllerImplWithArcTest,
1374 ArcAppPinCrossPlatformWorkflow) {
1375 // Work on ARC disabled platform first.
1376 const std::string arc_app_id1 =
1377 ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
1378 const std::string arc_app_id2 =
1379 ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
1380 const std::string arc_app_id3 =
1381 ArcAppTest::GetAppId(arc_test_.fake_apps()[2]);
1382
1383 InitLauncherController();
1384
1385 extension_service_->AddExtension(extension1_.get());
1386 extension_service_->AddExtension(extension2_.get());
1387 extension_service_->AddExtension(extension3_.get());
1388
1389 // extension 1, 3 are pinned by user
1390 syncer::SyncChangeList sync_list;
1391 InsertAddPinChange(&sync_list, 0, extension1_->id());
1392 InsertAddPinChange(&sync_list, 1, arc_app_id1);
1393 InsertAddPinChange(&sync_list, 2, extension2_->id());
1394 InsertAddPinChange(&sync_list, 3, arc_app_id2);
1395 InsertAddPinChange(&sync_list, 4, extension3_->id());
1396 SendPinChanges(sync_list, true);
1397 SetShelfChromeIconIndex(1);
1398
1399 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1400 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
1401 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1402 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
1403 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1404 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1405 EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus());
1406
1407 // Persist pin state, we don't have active pin for ARC apps yet, but pin
1408 // model should have it.
1409 syncer::SyncDataList copy_sync_list =
1410 app_service_->GetAllSyncData(syncer::APP_LIST);
1411
1412 ResetLauncherController();
1413 SendPinChanges(syncer::SyncChangeList(), true);
1414 StopAppSyncService();
1415 EXPECT_EQ(0U, app_service_->sync_items().size());
1416
1417 // Move to ARC enabled platform, restart syncing with stored data.
1418 StartAppSyncService(copy_sync_list);
1419 RecreateLauncherController()->Init();
1420
1421 // Pins must be automatically updated.
1422 SendListOfArcApps();
1423 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1424 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
1425 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1426 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
1427 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1428 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1429
1430 EXPECT_EQ("AppList, App1, Chrome, Fake App 0, App2, Fake App 1, App3",
1431 GetPinnedAppStatus());
1432
1433 // Now move pins on ARC enabled platform.
1434 model_->Move(1, 4);
1435 model_->Move(3, 1);
1436 model_->Move(3, 5);
1437 model_->Move(4, 2);
1438 EXPECT_EQ("AppList, App2, Fake App 1, Chrome, App1, Fake App 0, App3",
1439 GetPinnedAppStatus());
1440
1441 copy_sync_list = app_service_->GetAllSyncData(syncer::APP_LIST);
1442
1443 ResetLauncherController();
1444 ResetPinModel();
1445
1446 SendPinChanges(syncer::SyncChangeList(), true);
1447 StopAppSyncService();
1448 EXPECT_EQ(0U, app_service_->sync_items().size());
1449
1450 // Move back to ARC disabled platform.
1451 // TODO(victorhsieh): Implement opt-out.
1452 if (arc::ShouldArcAlwaysStart())
1453 return;
1454 EnablePlayStore(false);
1455 StartAppSyncService(copy_sync_list);
1456 RecreateLauncherController()->Init();
1457
1458 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1459 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
1460 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1461 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
1462 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1463 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1464 EXPECT_EQ("AppList, App2, Chrome, App1, App3", GetPinnedAppStatus());
1465
1466 // Now move/remove pins on ARC disabled platform.
1467 model_->Move(4, 2);
1468 launcher_controller_->UnpinAppWithID(extension2_->id());
1469 EXPECT_EQ("AppList, App3, Chrome, App1", GetPinnedAppStatus());
1470 EnablePlayStore(true);
1471
1472 SendListOfArcApps();
1473
1474 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1475 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
1476 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1477 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
1478 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1479 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id3));
1480 EXPECT_EQ("AppList, Fake App 1, App3, Chrome, App1, Fake App 0",
1481 GetPinnedAppStatus());
1482 }
1483
1484 /*
1485 * Test ChromeLauncherControllerImpl correctly merges policy pinned apps
1486 * and user pinned apps
1487 */
1488 TEST_F(ChromeLauncherControllerImplTest, MergePolicyAndUserPrefPinnedApps) {
1489 InitLauncherController();
1490
1491 extension_service_->AddExtension(extension1_.get());
1492 extension_service_->AddExtension(extension3_.get());
1493 extension_service_->AddExtension(extension4_.get());
1494 extension_service_->AddExtension(extension5_.get());
1495 // extension 1, 3 are pinned by user
1496 syncer::SyncChangeList sync_list;
1497 InsertAddPinChange(&sync_list, 0, extension1_->id());
1498 InsertAddPinChange(&sync_list, 1, extension_misc::kChromeAppId);
1499 InsertAddPinChange(&sync_list, 2, extension3_->id());
1500 SendPinChanges(sync_list, true);
1501
1502 base::ListValue policy_value;
1503 // extension 2 4 are pinned by policy
1504 InsertPrefValue(&policy_value, 0, extension2_->id());
1505 InsertPrefValue(&policy_value, 1, extension4_->id());
1506 profile()->GetTestingPrefService()->SetManagedPref(
1507 prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
1508
1509 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1510 // 2 is not pinned as it's not installed
1511 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1512 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1513 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
1514 // install extension 2 and check
1515 extension_service_->AddExtension(extension2_.get());
1516 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1517
1518 // Check user can manually pin or unpin these apps
1519 EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
1520 GetPinnableForAppID(extension1_->id(), profile()));
1521 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
1522 GetPinnableForAppID(extension2_->id(), profile()));
1523 EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE,
1524 GetPinnableForAppID(extension3_->id(), profile()));
1525 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
1526 GetPinnableForAppID(extension4_->id(), profile()));
1527
1528 // Check the order of shelf pinned apps
1529 EXPECT_EQ("AppList, App2, App4, App1, Chrome, App3", GetPinnedAppStatus());
1530 }
1531
1532 // Check that the restauration of launcher items is happening in the same order
1533 // as the user has pinned them (on another system) when they are synced reverse
1534 // order.
1535 TEST_F(ChromeLauncherControllerImplTest, RestoreDefaultAppsReverseOrder) {
1536 InitLauncherController();
1537
1538 syncer::SyncChangeList sync_list;
1539 InsertAddPinChange(&sync_list, 0, extension1_->id());
1540 InsertAddPinChange(&sync_list, 1, extension2_->id());
1541 InsertAddPinChange(&sync_list, 2, extension3_->id());
1542 SendPinChanges(sync_list, true);
1543
1544 // The model should only contain the browser shortcut and app list items.
1545 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1546 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1547 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1548 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1549
1550 // Installing |extension3_| should add it to the shelf - behind the
1551 // chrome icon.
1552 ash::ShelfItem item;
1553 extension_service_->AddExtension(extension3_.get());
1554 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1555 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1556 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1557
1558 // Installing |extension2_| should add it to the launcher - behind the
1559 // chrome icon, but in first location.
1560 extension_service_->AddExtension(extension2_.get());
1561 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1562 EXPECT_EQ("AppList, Chrome, App2, App3", GetPinnedAppStatus());
1563
1564 // Installing |extension1_| should add it to the launcher - behind the
1565 // chrome icon, but in first location.
1566 extension_service_->AddExtension(extension1_.get());
1567 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1568 }
1569
1570 // Check that the restauration of launcher items is happening in the same order
1571 // as the user has pinned them (on another system) when they are synced random
1572 // order.
1573 TEST_F(ChromeLauncherControllerImplTest, RestoreDefaultAppsRandomOrder) {
1574 InitLauncherController();
1575
1576 syncer::SyncChangeList sync_list;
1577 InsertAddPinChange(&sync_list, 0, extension1_->id());
1578 InsertAddPinChange(&sync_list, 1, extension2_->id());
1579 InsertAddPinChange(&sync_list, 2, extension3_->id());
1580 SendPinChanges(sync_list, true);
1581
1582 // The model should only contain the browser shortcut and app list items.
1583 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1584 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1585 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1586 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1587
1588 // Installing |extension2_| should add it to the launcher - behind the
1589 // chrome icon.
1590 extension_service_->AddExtension(extension2_.get());
1591 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1592 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1593 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1594
1595 // Installing |extension1_| should add it to the launcher - behind the
1596 // chrome icon, but in first location.
1597 extension_service_->AddExtension(extension1_.get());
1598 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1599 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
1600
1601 // Installing |extension3_| should add it to the launcher - behind the
1602 // chrome icon, but in first location.
1603 extension_service_->AddExtension(extension3_.get());
1604 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1605 }
1606
1607 // Check that the restauration of launcher items is happening in the same order
1608 // as the user has pinned / moved them (on another system) when they are synced
1609 // random order - including the chrome icon.
1610 TEST_F(ChromeLauncherControllerImplTest,
1611 RestoreDefaultAppsRandomOrderChromeMoved) {
1612 InitLauncherController();
1613
1614 syncer::SyncChangeList sync_list;
1615 InsertAddPinChange(&sync_list, 0, extension1_->id());
1616 InsertAddPinChange(&sync_list, 1, extension_misc::kChromeAppId);
1617 InsertAddPinChange(&sync_list, 2, extension2_->id());
1618 InsertAddPinChange(&sync_list, 3, extension3_->id());
1619 SendPinChanges(sync_list, true);
1620
1621 // The model should only contain the browser shortcut and app list items.
1622 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1623 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1624 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1625 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1626
1627 // Installing |extension2_| should add it to the shelf - behind the
1628 // chrome icon.
1629 ash::ShelfItem item;
1630 extension_service_->AddExtension(extension2_.get());
1631 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1632 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1633 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1634
1635 // Installing |extension1_| should add it to the launcher - behind the
1636 // chrome icon, but in first location.
1637 extension_service_->AddExtension(extension1_.get());
1638 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1639 EXPECT_EQ("AppList, App1, Chrome, App2", GetPinnedAppStatus());
1640
1641 // Installing |extension3_| should add it to the launcher - behind the
1642 // chrome icon, but in first location.
1643 extension_service_->AddExtension(extension3_.get());
1644 EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus());
1645 }
1646
1647 // Check that syncing to a different state does the correct thing.
1648 TEST_F(ChromeLauncherControllerImplTest, RestoreDefaultAppsResyncOrder) {
1649 InitLauncherController();
1650
1651 syncer::SyncChangeList sync_list0;
1652 InsertAddPinChange(&sync_list0, 0, extension1_->id());
1653 InsertAddPinChange(&sync_list0, 1, extension2_->id());
1654 InsertAddPinChange(&sync_list0, 2, extension3_->id());
1655 SendPinChanges(sync_list0, true);
1656
1657 // The shelf layout has always one static item at the beginning (App List).
1658 extension_service_->AddExtension(extension2_.get());
1659 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1660 extension_service_->AddExtension(extension1_.get());
1661 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
1662 extension_service_->AddExtension(extension3_.get());
1663 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1664
1665 // Change the order with increasing chrome position and decreasing position.
1666 syncer::SyncChangeList sync_list1;
1667 InsertAddPinChange(&sync_list1, 0, extension3_->id());
1668 InsertAddPinChange(&sync_list1, 1, extension1_->id());
1669 InsertAddPinChange(&sync_list1, 2, extension2_->id());
1670 InsertAddPinChange(&sync_list1, 3, extension_misc::kChromeAppId);
1671 SendPinChanges(sync_list1, true);
1672 EXPECT_EQ("AppList, App3, App1, App2, Chrome", GetPinnedAppStatus());
1673
1674 syncer::SyncChangeList sync_list2;
1675 InsertAddPinChange(&sync_list2, 0, extension2_->id());
1676 InsertAddPinChange(&sync_list2, 1, extension3_->id());
1677 InsertAddPinChange(&sync_list2, 2, extension_misc::kChromeAppId);
1678 InsertAddPinChange(&sync_list2, 3, extension1_->id());
1679 SendPinChanges(sync_list2, true);
1680 EXPECT_EQ("AppList, App2, App3, Chrome, App1", GetPinnedAppStatus());
1681
1682 // Check that the chrome icon can also be at the first possible location.
1683 syncer::SyncChangeList sync_list3;
1684 InsertAddPinChange(&sync_list3, 0, extension3_->id());
1685 InsertAddPinChange(&sync_list3, 1, extension2_->id());
1686 InsertAddPinChange(&sync_list3, 2, extension1_->id());
1687 SendPinChanges(sync_list3, true);
1688 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1689
1690 // Check that unloading of extensions works as expected.
1691 extension_service_->UnloadExtension(extension1_->id(),
1692 UnloadedExtensionInfo::REASON_UNINSTALL);
1693 EXPECT_EQ("AppList, Chrome, App3, App2", GetPinnedAppStatus());
1694
1695 extension_service_->UnloadExtension(extension2_->id(),
1696 UnloadedExtensionInfo::REASON_UNINSTALL);
1697 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1698
1699 // Check that an update of an extension does not crash the system.
1700 extension_service_->UnloadExtension(extension3_->id(),
1701 UnloadedExtensionInfo::REASON_UPDATE);
1702 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1703 }
1704
1705 // Test the V1 app interaction flow: run it, activate it, close it.
1706 TEST_F(ChromeLauncherControllerImplTest, V1AppRunActivateClose) {
1707 InitLauncherController();
1708 // The model should only contain the browser shortcut and app list items.
1709 EXPECT_EQ(2, model_->item_count());
1710 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1711 EXPECT_EQ(ash::kInvalidShelfID,
1712 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1713
1714 // Reporting that the app is running should create a new shelf item.
1715 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1716 EXPECT_EQ(3, model_->item_count());
1717 EXPECT_EQ(ash::TYPE_APP, model_->items()[2].type);
1718 EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
1719 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1720 EXPECT_NE(ash::kInvalidShelfID,
1721 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1722
1723 // Reporting an active status should just update the existing item.
1724 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_ACTIVE);
1725 EXPECT_EQ(3, model_->item_count());
1726 EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[2].status);
1727
1728 // Reporting that the app is closed should remove its shelf item.
1729 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1730 EXPECT_EQ(2, model_->item_count());
1731 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1732 EXPECT_EQ(ash::kInvalidShelfID,
1733 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1734
1735 // Reporting that the app is closed again should have no effect.
1736 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1737 EXPECT_EQ(2, model_->item_count());
1738 }
1739
1740 // Test the V1 app interaction flow: pin it, run it, close it, unpin it.
1741 TEST_F(ChromeLauncherControllerImplTest, V1AppPinRunCloseUnpin) {
1742 InitLauncherController();
1743 // The model should only contain the browser shortcut and app list items.
1744 EXPECT_EQ(2, model_->item_count());
1745 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1746 EXPECT_EQ(ash::kInvalidShelfID,
1747 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1748
1749 // Pinning the app should create a new shelf item.
1750 launcher_controller_->PinAppWithID(extension1_->id());
1751 EXPECT_EQ(3, model_->item_count());
1752 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1753 EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
1754 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1755 EXPECT_NE(ash::kInvalidShelfID,
1756 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1757
1758 // Reporting that the app is running should just update the existing item.
1759 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1760 EXPECT_EQ(3, model_->item_count());
1761 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1762 EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
1763 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1764 EXPECT_NE(ash::kInvalidShelfID,
1765 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1766
1767 // Reporting that the app is closed should just update the existing item.
1768 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1769 EXPECT_EQ(3, model_->item_count());
1770 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1771 EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
1772 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1773 EXPECT_NE(ash::kInvalidShelfID,
1774 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1775
1776 // Unpinning the app should remove its shelf item.
1777 launcher_controller_->UnpinAppWithID(extension1_->id());
1778 EXPECT_EQ(2, model_->item_count());
1779 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1780 EXPECT_EQ(ash::kInvalidShelfID,
1781 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1782 }
1783
1784 // Test the V1 app interaction flow: run it, pin it, close it, unpin it.
1785 TEST_F(ChromeLauncherControllerImplTest, V1AppRunPinCloseUnpin) {
1786 InitLauncherController();
1787 // The model should only contain the browser shortcut and app list items.
1788 EXPECT_EQ(2, model_->item_count());
1789 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1790 EXPECT_EQ(ash::kInvalidShelfID,
1791 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1792
1793 // Reporting that the app is running should create a new shelf item.
1794 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1795 EXPECT_EQ(3, model_->item_count());
1796 EXPECT_EQ(ash::TYPE_APP, model_->items()[2].type);
1797 EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
1798 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1799 EXPECT_NE(ash::kInvalidShelfID,
1800 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1801
1802 // Pinning the app should just update the existing item.
1803 launcher_controller_->PinAppWithID(extension1_->id());
1804 EXPECT_EQ(3, model_->item_count());
1805 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1806 EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
1807 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1808 EXPECT_NE(ash::kInvalidShelfID,
1809 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1810
1811 // Reporting that the app is closed should just update the existing item.
1812 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1813 EXPECT_EQ(3, model_->item_count());
1814 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1815 EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
1816 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1817 EXPECT_NE(ash::kInvalidShelfID,
1818 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1819
1820 // Unpinning the app should remove its shelf item.
1821 launcher_controller_->UnpinAppWithID(extension1_->id());
1822 EXPECT_EQ(2, model_->item_count());
1823 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1824 EXPECT_EQ(ash::kInvalidShelfID,
1825 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1826 }
1827
1828 // Test the V1 app interaction flow: pin it, run it, unpin it, close it.
1829 TEST_F(ChromeLauncherControllerImplTest, V1AppPinRunUnpinClose) {
1830 InitLauncherController();
1831 // The model should only contain the browser shortcut and app list items.
1832 EXPECT_EQ(2, model_->item_count());
1833 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1834 EXPECT_EQ(ash::kInvalidShelfID,
1835 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1836
1837 // Pinning the app should create a new shelf item.
1838 launcher_controller_->PinAppWithID(extension1_->id());
1839 EXPECT_EQ(3, model_->item_count());
1840 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1841 EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
1842 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1843 EXPECT_NE(ash::kInvalidShelfID,
1844 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1845
1846 // Reporting that the app is running should just update the existing item.
1847 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1848 EXPECT_EQ(3, model_->item_count());
1849 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
1850 EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
1851 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1852 EXPECT_NE(ash::kInvalidShelfID,
1853 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1854
1855 // Unpinning the app should just update the existing item.
1856 launcher_controller_->UnpinAppWithID(extension1_->id());
1857 EXPECT_EQ(3, model_->item_count());
1858 EXPECT_EQ(ash::TYPE_APP, model_->items()[2].type);
1859 EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
1860 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1861 EXPECT_NE(ash::kInvalidShelfID,
1862 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1863
1864 // Reporting that the app is closed should remove its shelf item.
1865 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1866 EXPECT_EQ(2, model_->item_count());
1867 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1868 EXPECT_EQ(ash::kInvalidShelfID,
1869 launcher_controller_->GetShelfIDForAppID(extension1_->id()));
1870 }
1871
1872 // Ensure unpinned V1 app ordering is properly restored after user changes.
1873 TEST_F(ChromeLauncherControllerImplTest, CheckRunningV1AppOrder) {
1874 InitLauncherController();
1875 // The model should only contain the browser shortcut and app list items.
1876 EXPECT_EQ(2, model_->item_count());
1877
1878 // Add a few running applications.
1879 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
1880 launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_RUNNING);
1881 launcher_controller_->SetV1AppStatus(extension3_->id(), ash::STATUS_RUNNING);
1882 EXPECT_EQ(5, model_->item_count());
1883 // Note that this not only checks the order of applications but also the
1884 // running type.
1885 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
1886
1887 // Remember the current order of applications for the current user.
1888 const AccountId& current_account_id =
1889 multi_user_util::GetAccountIdFromProfile(profile());
1890 RememberUnpinnedRunningApplicationOrder();
1891
1892 // Switch some items and check that restoring a user which was not yet
1893 // remembered changes nothing.
1894 model_->Move(2, 3);
1895 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
1896 const AccountId second_fake_account_id(
1897 AccountId::FromUserEmail("second-fake-user@fake.com"));
1898 RestoreUnpinnedRunningApplicationOrder(second_fake_account_id);
1899 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
1900
1901 // Restoring the stored user should however do the right thing.
1902 RestoreUnpinnedRunningApplicationOrder(current_account_id);
1903 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
1904
1905 // Switch again some items and even delete one - making sure that the missing
1906 // item gets properly handled.
1907 model_->Move(3, 4);
1908 launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
1909 EXPECT_EQ("AppList, Chrome, app3, app2", GetPinnedAppStatus());
1910 RestoreUnpinnedRunningApplicationOrder(current_account_id);
1911 EXPECT_EQ("AppList, Chrome, app2, app3", GetPinnedAppStatus());
1912
1913 // Check that removing more items does not crash and changes nothing.
1914 launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_CLOSED);
1915 RestoreUnpinnedRunningApplicationOrder(current_account_id);
1916 EXPECT_EQ("AppList, Chrome, app3", GetPinnedAppStatus());
1917 launcher_controller_->SetV1AppStatus(extension3_->id(), ash::STATUS_CLOSED);
1918 RestoreUnpinnedRunningApplicationOrder(current_account_id);
1919 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1920 }
1921
1922 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcDeferredLaunch) {
1923 InitLauncherController();
1924
1925 const arc::mojom::AppInfo& app1 = arc_test_.fake_apps()[0];
1926 const arc::mojom::AppInfo& app2 = arc_test_.fake_apps()[1];
1927 const arc::mojom::AppInfo& app3 = arc_test_.fake_apps()[2];
1928 const arc::mojom::ShortcutInfo& shortcut = arc_test_.fake_shortcuts()[0];
1929 const std::string arc_app_id1 = ArcAppTest::GetAppId(app1);
1930 const std::string arc_app_id2 = ArcAppTest::GetAppId(app2);
1931 const std::string arc_app_id3 = ArcAppTest::GetAppId(app3);
1932 const std::string arc_shortcut_id = ArcAppTest::GetAppId(shortcut);
1933
1934 SendListOfArcApps();
1935 SendListOfArcShortcuts();
1936
1937 arc_test_.StopArcInstance();
1938
1939 EXPECT_EQ(ash::kInvalidShelfID,
1940 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
1941 EXPECT_EQ(ash::kInvalidShelfID,
1942 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
1943 EXPECT_EQ(ash::kInvalidShelfID,
1944 launcher_controller_->GetShelfIDForAppID(arc_app_id3));
1945 EXPECT_EQ(ash::kInvalidShelfID,
1946 launcher_controller_->GetShelfIDForAppID(arc_shortcut_id));
1947
1948 arc::LaunchApp(profile(), arc_app_id1, ui::EF_LEFT_MOUSE_BUTTON);
1949 arc::LaunchApp(profile(), arc_app_id1, ui::EF_LEFT_MOUSE_BUTTON);
1950 arc::LaunchApp(profile(), arc_app_id2, ui::EF_LEFT_MOUSE_BUTTON);
1951 arc::LaunchApp(profile(), arc_app_id3, ui::EF_LEFT_MOUSE_BUTTON);
1952 arc::LaunchApp(profile(), arc_shortcut_id, ui::EF_LEFT_MOUSE_BUTTON);
1953
1954 const ash::ShelfID shelf_id_app_1 =
1955 launcher_controller_->GetShelfIDForAppID(arc_app_id1);
1956 const ash::ShelfID shelf_id_app_2 =
1957 launcher_controller_->GetShelfIDForAppID(arc_app_id2);
1958 const ash::ShelfID shelf_id_app_3 =
1959 launcher_controller_->GetShelfIDForAppID(arc_app_id3);
1960 const ash::ShelfID shelf_id_shortcut =
1961 launcher_controller_->GetShelfIDForAppID(arc_shortcut_id);
1962 EXPECT_NE(ash::kInvalidShelfID, shelf_id_app_1);
1963 EXPECT_NE(ash::kInvalidShelfID, shelf_id_app_2);
1964 EXPECT_NE(ash::kInvalidShelfID, shelf_id_app_3);
1965 EXPECT_NE(ash::kInvalidShelfID, shelf_id_shortcut);
1966
1967 // We activated arc_app_id1 twice but expect one close for item controller
1968 // stops launching request.
1969 ash::ShelfItemDelegate* item_delegate =
1970 model_->GetShelfItemDelegate(shelf_id_app_1);
1971 ASSERT_NE(nullptr, item_delegate);
1972 item_delegate->Close();
1973 base::RunLoop().RunUntilIdle();
1974
1975 EXPECT_EQ(ash::kInvalidShelfID,
1976 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
1977 EXPECT_EQ(shelf_id_app_2,
1978 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
1979 EXPECT_EQ(shelf_id_app_3,
1980 launcher_controller_->GetShelfIDForAppID(arc_app_id3));
1981
1982 arc_test_.RestartArcInstance();
1983 SendListOfArcApps();
1984
1985 base::RunLoop().RunUntilIdle();
1986
1987 // Now deferred contollers should go away together with shelf items and ARC
1988 // app instance should receive request for launching apps and shortcuts.
1989 EXPECT_EQ(ash::kInvalidShelfID,
1990 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
1991 EXPECT_EQ(ash::kInvalidShelfID,
1992 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
1993 EXPECT_EQ(ash::kInvalidShelfID,
1994 launcher_controller_->GetShelfIDForAppID(arc_app_id3));
1995
1996 ASSERT_EQ(2U, arc_test_.app_instance()->launch_requests().size());
1997 ASSERT_EQ(1U, arc_test_.app_instance()->launch_intents().size());
1998
1999 const arc::FakeAppInstance::Request* request1 =
2000 arc_test_.app_instance()->launch_requests()[0].get();
2001 const arc::FakeAppInstance::Request* request2 =
2002 arc_test_.app_instance()->launch_requests()[1].get();
2003
2004 EXPECT_TRUE((request1->IsForApp(app2) && request2->IsForApp(app3)) ||
2005 (request1->IsForApp(app3) && request2->IsForApp(app2)));
2006 EXPECT_EQ(arc_test_.app_instance()->launch_intents()[0].c_str(),
2007 shortcut.intent_uri);
2008 }
2009
2010 // Ensure the deferred controller does not override the active app controller
2011 // (crbug.com/701152).
2012 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcDeferredLaunchForActiveApp) {
2013 InitLauncherController();
2014 SendListOfArcApps();
2015 arc_test_.StopArcInstance();
2016
2017 const arc::mojom::AppInfo& app = arc_test_.fake_apps()[0];
2018 const std::string app_id = ArcAppTest::GetAppId(app);
2019
2020 launcher_controller_->PinAppWithID(app_id);
2021 EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
2022 const ash::ShelfID shelf_id =
2023 launcher_controller_->GetShelfIDForAppID(app_id);
2024 EXPECT_NE(ash::kInvalidShelfID, shelf_id);
2025
2026 int item_index = model_->ItemIndexByID(shelf_id);
2027 ASSERT_GE(item_index, 0);
2028
2029 EXPECT_EQ(model_->items()[item_index].status, ash::STATUS_CLOSED);
2030 EXPECT_EQ(model_->items()[item_index].type, ash::TYPE_PINNED_APP);
2031
2032 // Play Store app is ARC app that might be represented by native Chrome
2033 // platform app.
2034 model_->SetShelfItemDelegate(
2035 shelf_id, base::MakeUnique<ExtensionAppWindowLauncherItemController>(
2036 ash::AppLaunchId(app_id)));
2037 launcher_controller_->SetItemStatus(shelf_id, ash::STATUS_RUNNING);
2038
2039 // This launch request should be ignored in case of active app.
2040 arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON);
2041 EXPECT_FALSE(launcher_controller_->GetArcDeferredLauncher()->HasApp(app_id));
2042
2043 // Close app but shortcut should exist.
2044 launcher_controller_->CloseLauncherItem(shelf_id);
2045 EXPECT_EQ(shelf_id, launcher_controller_->GetShelfIDForAppID(app_id));
2046
2047 // This should switch shelf item into closed state.
2048 item_index = model_->ItemIndexByID(shelf_id);
2049 ASSERT_GE(item_index, 0);
2050 EXPECT_EQ(model_->items()[item_index].status, ash::STATUS_CLOSED);
2051 EXPECT_EQ(model_->items()[item_index].type, ash::TYPE_PINNED_APP);
2052
2053 // Now launch request should not be ignored.
2054 arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON);
2055 EXPECT_TRUE(launcher_controller_->GetArcDeferredLauncher()->HasApp(app_id));
2056 }
2057
2058 TEST_P(ChromeLauncherControllerImplMultiProfileWithArcTest, ArcMultiUser) {
2059 SendListOfArcApps();
2060
2061 InitLauncherController();
2062 // TODO(crbug.com/654622): This test breaks with a non-null static instance.
2063 ChromeLauncherControllerImpl::set_instance_for_test(nullptr);
2064
2065 SetLauncherControllerHelper(new TestLauncherControllerHelper);
2066
2067 // App1 exists all the time.
2068 // App2 is created when primary user is active and destroyed when secondary
2069 // user is active.
2070 // App3 created when secondary user is active.
2071
2072 const std::string user2 = "user2";
2073 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2074 const AccountId account_id(
2075 multi_user_util::GetAccountIdFromProfile(profile()));
2076 const AccountId account_id2(
2077 multi_user_util::GetAccountIdFromProfile(profile2));
2078
2079 const std::string arc_app_id1 =
2080 ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2081 const std::string arc_app_id2 =
2082 ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
2083 const std::string arc_app_id3 =
2084 ArcAppTest::GetAppId(arc_test_.fake_apps()[2]);
2085
2086 std::string window_app_id1("org.chromium.arc.1");
2087 views::Widget* arc_window1 = CreateArcWindow(window_app_id1);
2088 arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2089 std::string());
2090 EXPECT_NE(ash::kInvalidShelfID,
2091 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2092
2093 std::string window_app_id2("org.chromium.arc.2");
2094 views::Widget* arc_window2 = CreateArcWindow(window_app_id2);
2095 arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1],
2096 std::string());
2097 EXPECT_NE(ash::kInvalidShelfID,
2098 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2099
2100 launcher_controller_->SetProfileForTest(profile2);
2101 SwitchActiveUser(account_id2);
2102
2103 EXPECT_EQ(ash::kInvalidShelfID,
2104 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2105 EXPECT_EQ(ash::kInvalidShelfID,
2106 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2107
2108 std::string window_app_id3("org.chromium.arc.3");
2109 views::Widget* arc_window3 = CreateArcWindow(window_app_id3);
2110 arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[2],
2111 std::string());
2112 EXPECT_EQ(ash::kInvalidShelfID,
2113 launcher_controller_->GetShelfIDForAppID(arc_app_id3));
2114
2115 arc_window2->CloseNow();
2116 arc_test_.app_instance()->SendTaskDestroyed(2);
2117
2118 launcher_controller_->SetProfileForTest(profile());
2119 SwitchActiveUser(account_id);
2120
2121 EXPECT_NE(ash::kInvalidShelfID,
2122 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2123 EXPECT_EQ(ash::kInvalidShelfID,
2124 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2125 EXPECT_NE(ash::kInvalidShelfID,
2126 launcher_controller_->GetShelfIDForAppID(arc_app_id3));
2127
2128 // Close active window to let test passes.
2129 arc_window1->CloseNow();
2130 arc_window3->CloseNow();
2131 }
2132
2133 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcRunningApp) {
2134 InitLauncherController();
2135
2136 const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2137 SendListOfArcApps();
2138 EXPECT_EQ(ash::kInvalidShelfID,
2139 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2140
2141 // Normal flow, create/destroy tasks.
2142 std::string window_app_id1("org.chromium.arc.1");
2143 std::string window_app_id2("org.chromium.arc.2");
2144 std::string window_app_id3("org.chromium.arc.3");
2145 CreateArcWindow(window_app_id1);
2146 arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2147 std::string());
2148 EXPECT_NE(ash::kInvalidShelfID,
2149 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2150 CreateArcWindow(window_app_id2);
2151 arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[0],
2152 std::string());
2153 EXPECT_NE(ash::kInvalidShelfID,
2154 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2155 arc_test_.app_instance()->SendTaskDestroyed(1);
2156 EXPECT_NE(ash::kInvalidShelfID,
2157 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2158 arc_test_.app_instance()->SendTaskDestroyed(2);
2159 EXPECT_EQ(ash::kInvalidShelfID,
2160 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2161
2162 // Stopping bridge removes apps.
2163 CreateArcWindow(window_app_id3);
2164 arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[0],
2165 std::string());
2166 EXPECT_NE(ash::kInvalidShelfID,
2167 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2168 arc_test_.StopArcInstance();
2169 base::RunLoop().RunUntilIdle();
2170 EXPECT_EQ(ash::kInvalidShelfID,
2171 launcher_controller_->GetShelfIDForAppID(arc_app_id));
2172 }
2173
2174 // Test race creation/deletion of ARC app.
2175 // TODO(khmel): Remove after moving everything to wayland protocol.
2176 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcRaceCreateClose) {
2177 InitLauncherController();
2178
2179 const std::string arc_app_id1 =
2180 ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2181 const std::string arc_app_id2 =
2182 ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
2183 SendListOfArcApps();
2184
2185 // ARC window created before and closed after mojom notification.
2186 std::string window_app_id1("org.chromium.arc.1");
2187 views::Widget* arc_window = CreateArcWindow(window_app_id1);
2188 EXPECT_EQ(ash::kInvalidShelfID,
2189 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2190 ASSERT_TRUE(arc_window);
2191 arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2192 std::string());
2193 EXPECT_NE(ash::kInvalidShelfID,
2194 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2195 arc_test_.app_instance()->SendTaskDestroyed(1);
2196 EXPECT_EQ(ash::kInvalidShelfID,
2197 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2198 arc_window->Close();
2199 base::RunLoop().RunUntilIdle();
2200 EXPECT_EQ(ash::kInvalidShelfID,
2201 launcher_controller_->GetShelfIDForAppID(arc_app_id1));
2202
2203 // ARC window created after and closed before mojom notification.
2204 std::string window_app_id2("org.chromium.arc.2");
2205 arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[1],
2206 std::string());
2207 EXPECT_NE(ash::kInvalidShelfID,
2208 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2209 arc_window = CreateArcWindow(window_app_id2);
2210 ASSERT_TRUE(arc_window);
2211 EXPECT_NE(ash::kInvalidShelfID,
2212 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2213 arc_window->Close();
2214 base::RunLoop().RunUntilIdle();
2215 // Closing window does not close shelf item. It is closed on task destroy.
2216 EXPECT_NE(ash::kInvalidShelfID,
2217 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2218 arc_test_.app_instance()->SendTaskDestroyed(2);
2219 EXPECT_EQ(ash::kInvalidShelfID,
2220 launcher_controller_->GetShelfIDForAppID(arc_app_id2));
2221 }
2222
2223 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcWindowRecreation) {
2224 InitLauncherController();
2225
2226 const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2227 SendListOfArcApps();
2228
2229 std::string window_app_id("org.chromium.arc.1");
2230 views::Widget* arc_window = CreateArcWindow(window_app_id);
2231 ASSERT_TRUE(arc_window);
2232 arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0],
2233 std::string());
2234 const ash::ShelfID shelf_id =
2235 launcher_controller_->GetShelfIDForAppID(arc_app_id);
2236 EXPECT_NE(ash::kInvalidShelfID, shelf_id);
2237
2238 for (int i = 0; i < 3; ++i) {
2239 arc_window->Close();
2240 base::RunLoop().RunUntilIdle();
2241 EXPECT_EQ(shelf_id, launcher_controller_->GetShelfIDForAppID(arc_app_id));
2242
2243 arc_window = CreateArcWindow(window_app_id);
2244 ASSERT_TRUE(arc_window);
2245 base::RunLoop().RunUntilIdle();
2246 EXPECT_EQ(shelf_id, launcher_controller_->GetShelfIDForAppID(arc_app_id));
2247 }
2248 }
2249
2250 // Validate that ARC app is pinned correctly and pin is removed automatically
2251 // once app is uninstalled.
2252 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcAppPin) {
2253 InitLauncherController();
2254
2255 const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2256
2257 SendListOfArcApps();
2258 extension_service_->AddExtension(extension1_.get());
2259 extension_service_->AddExtension(extension2_.get());
2260
2261 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
2262 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id));
2263 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
2264
2265 launcher_controller_->PinAppWithID(extension1_->id());
2266 launcher_controller_->PinAppWithID(arc_app_id);
2267 launcher_controller_->PinAppWithID(extension2_->id());
2268
2269 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2270 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id));
2271 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2272
2273 EXPECT_EQ("AppList, Chrome, App1, Fake App 0, App2", GetPinnedAppStatus());
2274 // In opt-out mode, only system apps are available and can't be uninstalled.
2275 // Skip the rest of the test.
2276 if (arc::ShouldArcAlwaysStart())
2277 return;
2278 UninstallArcApps();
2279 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id));
2280 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
2281 SendListOfArcApps();
2282 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id));
2283 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
2284
2285 // Opt-Out/Opt-In remove item from the shelf.
2286 launcher_controller_->PinAppWithID(arc_app_id);
2287 EXPECT_EQ("AppList, Chrome, App1, App2, Fake App 0", GetPinnedAppStatus());
2288 EnablePlayStore(false);
2289 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
2290 EnablePlayStore(true);
2291 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
2292 SendListOfArcApps();
2293 EXPECT_EQ("AppList, Chrome, App1, App2, Fake App 0", GetPinnedAppStatus());
2294 }
2295
2296 // Validates that ARC app pins persist across OptOut/OptIn.
2297 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcAppPinOptOutOptIn) {
2298 InitLauncherController();
2299
2300 const std::string arc_app_id1 =
2301 ArcAppTest::GetAppId(arc_test_.fake_apps()[0]);
2302 const std::string arc_app_id2 =
2303 ArcAppTest::GetAppId(arc_test_.fake_apps()[1]);
2304
2305 SendListOfArcApps();
2306 extension_service_->AddExtension(extension1_.get());
2307 extension_service_->AddExtension(extension2_.get());
2308
2309 launcher_controller_->PinAppWithID(extension1_->id());
2310 launcher_controller_->PinAppWithID(arc_app_id2);
2311 launcher_controller_->PinAppWithID(extension2_->id());
2312 launcher_controller_->PinAppWithID(arc_app_id1);
2313
2314 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2315 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
2316 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2317 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
2318 EXPECT_EQ("AppList, Chrome, App1, Fake App 1, App2, Fake App 0",
2319 GetPinnedAppStatus());
2320
2321 // TODO(victorhsieh): Implement opt-out.
2322 if (arc::ShouldArcAlwaysStart())
2323 return;
2324 EnablePlayStore(false);
2325
2326 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
2327 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2328 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id1));
2329 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2330 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id2));
2331
2332 EnablePlayStore(true);
2333 SendListOfArcApps();
2334 base::RunLoop().RunUntilIdle();
2335
2336 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2337 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id1));
2338 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2339 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id2));
2340
2341 EXPECT_EQ("AppList, Chrome, App1, Fake App 1, App2, Fake App 0",
2342 GetPinnedAppStatus());
2343 }
2344
2345 // Check that with multi profile V1 apps are properly added / removed from the
2346 // shelf.
2347 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
2348 V1AppUpdateOnUserSwitch) {
2349 // Create a browser item in the LauncherController.
2350 InitLauncherController();
2351
2352 EXPECT_EQ(2, model_->item_count());
2353 {
2354 // Create a "windowed gmail app".
2355 std::unique_ptr<V1App> v1_app(
2356 CreateRunningV1App(profile(), extension_misc::kGmailAppId, gmail_url));
2357 EXPECT_EQ(3, model_->item_count());
2358
2359 // After switching to a second user the item should be gone.
2360 std::string user2 = "user2";
2361 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2362 const AccountId account_id2(
2363 multi_user_util::GetAccountIdFromProfile(profile2));
2364 const AccountId account_id(
2365 multi_user_util::GetAccountIdFromProfile(profile()));
2366 SwitchActiveUser(account_id2);
2367 EXPECT_EQ(2, model_->item_count());
2368
2369 // After switching back the item should be back.
2370 SwitchActiveUser(account_id);
2371 EXPECT_EQ(3, model_->item_count());
2372 // Note we destroy now the gmail app with the closure end.
2373 }
2374 EXPECT_EQ(2, model_->item_count());
2375 }
2376
2377 // Check edge cases with multi profile V1 apps in the shelf.
2378 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
2379 V1AppUpdateOnUserSwitchEdgecases) {
2380 // Create a browser item in the LauncherController.
2381 InitLauncherController();
2382
2383 // First test: Create an app when the user is not active.
2384 std::string user2 = "user2";
2385 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2386 const AccountId account_id2(
2387 multi_user_util::GetAccountIdFromProfile(profile2));
2388 const AccountId account_id(
2389 multi_user_util::GetAccountIdFromProfile(profile()));
2390 {
2391 // Create a "windowed gmail app".
2392 std::unique_ptr<V1App> v1_app(
2393 CreateRunningV1App(profile2, extension_misc::kGmailAppId, gmail_url));
2394 EXPECT_EQ(2, model_->item_count());
2395
2396 // However - switching to the user should show it.
2397 SwitchActiveUser(account_id2);
2398 EXPECT_EQ(3, model_->item_count());
2399
2400 // Second test: Remove the app when the user is not active and see that it
2401 // works.
2402 SwitchActiveUser(account_id);
2403 EXPECT_EQ(2, model_->item_count());
2404 // Note: the closure ends and the browser will go away.
2405 }
2406 EXPECT_EQ(2, model_->item_count());
2407 SwitchActiveUser(account_id2);
2408 EXPECT_EQ(2, model_->item_count());
2409 SwitchActiveUser(account_id);
2410 EXPECT_EQ(2, model_->item_count());
2411 }
2412
2413 // Check edge case where a visiting V1 app gets closed (crbug.com/321374).
2414 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
2415 V1CloseOnVisitingDesktop) {
2416 // Create a browser item in the LauncherController.
2417 InitLauncherController();
2418
2419 chrome::MultiUserWindowManager* manager =
2420 chrome::MultiUserWindowManager::GetInstance();
2421
2422 // First create an app when the user is active.
2423 std::string user2 = "user2";
2424 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2425 const AccountId account_id(
2426 multi_user_util::GetAccountIdFromProfile(profile()));
2427 const AccountId account_id2(
2428 multi_user_util::GetAccountIdFromProfile(profile2));
2429 {
2430 // Create a "windowed gmail app".
2431 std::unique_ptr<V1App> v1_app(CreateRunningV1App(
2432 profile(), extension_misc::kGmailAppId, kGmailLaunchURL));
2433 EXPECT_EQ(3, model_->item_count());
2434
2435 // Transfer the app to the other screen and switch users.
2436 manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(),
2437 account_id2);
2438 EXPECT_EQ(3, model_->item_count());
2439 SwitchActiveUser(account_id2);
2440 EXPECT_EQ(2, model_->item_count());
2441 }
2442 // After the app was destroyed, switch back. (which caused already a crash).
2443 SwitchActiveUser(account_id);
2444
2445 // Create the same app again - which was also causing the crash.
2446 EXPECT_EQ(2, model_->item_count());
2447 {
2448 // Create a "windowed gmail app".
2449 std::unique_ptr<V1App> v1_app(CreateRunningV1App(
2450 profile(), extension_misc::kGmailAppId, kGmailLaunchURL));
2451 EXPECT_EQ(3, model_->item_count());
2452 }
2453 SwitchActiveUser(account_id2);
2454 EXPECT_EQ(2, model_->item_count());
2455 }
2456
2457 // Check edge cases with multi profile V1 apps in the shelf.
2458 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
2459 V1AppUpdateOnUserSwitchEdgecases2) {
2460 // Create a browser item in the LauncherController.
2461 InitLauncherController();
2462
2463 // First test: Create an app when the user is not active.
2464 std::string user2 = "user2";
2465 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2466 const AccountId account_id(
2467 multi_user_util::GetAccountIdFromProfile(profile()));
2468 const AccountId account_id2(
2469 multi_user_util::GetAccountIdFromProfile(profile2));
2470 SwitchActiveUser(account_id2);
2471 {
2472 // Create a "windowed gmail app".
2473 std::unique_ptr<V1App> v1_app(
2474 CreateRunningV1App(profile(), extension_misc::kGmailAppId, gmail_url));
2475 EXPECT_EQ(2, model_->item_count());
2476
2477 // However - switching to the user should show it.
2478 SwitchActiveUser(account_id);
2479 EXPECT_EQ(3, model_->item_count());
2480
2481 // Second test: Remove the app when the user is not active and see that it
2482 // works.
2483 SwitchActiveUser(account_id2);
2484 EXPECT_EQ(2, model_->item_count());
2485 v1_app.reset();
2486 }
2487 EXPECT_EQ(2, model_->item_count());
2488 SwitchActiveUser(account_id);
2489 EXPECT_EQ(2, model_->item_count());
2490 SwitchActiveUser(account_id2);
2491 EXPECT_EQ(2, model_->item_count());
2492 }
2493
2494 // Check that activating an item which is on another user's desktop, will bring
2495 // it back.
2496 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
2497 TestLauncherActivationPullsBackWindow) {
2498 // Create a browser item in the LauncherController.
2499 InitLauncherController();
2500 chrome::MultiUserWindowManager* manager =
2501 chrome::MultiUserWindowManager::GetInstance();
2502
2503 // Create a second test profile. The first is the one in profile() created in
2504 // BrowserWithTestWindowTest::SetUp().
2505 // No need to add the profiles to the MultiUserWindowManager here.
2506 // CreateMultiUserProfile() already does that.
2507 TestingProfile* profile2 = CreateMultiUserProfile("user2");
2508 const AccountId current_user =
2509 multi_user_util::GetAccountIdFromProfile(profile());
2510
2511 // Create a browser window with a native window for the current user.
2512 std::unique_ptr<Browser> browser(
2513 CreateBrowserWithTestWindowForProfile(profile()));
2514 BrowserWindow* browser_window = browser->window();
2515 aura::Window* window = browser_window->GetNativeWindow();
2516 manager->SetWindowOwner(window, current_user);
2517
2518 // Check that an activation of the window on its owner's desktop does not
2519 // change the visibility to another user.
2520 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false);
2521 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
2522
2523 // Transfer the window to another user's desktop and check that activating it
2524 // does pull it back to that user.
2525 manager->ShowWindowForUser(
2526 window, multi_user_util::GetAccountIdFromProfile(profile2));
2527 EXPECT_FALSE(manager->IsWindowOnDesktopOfUser(window, current_user));
2528 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false);
2529 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
2530 }
2531
2532 // Check that a running windowed V1 application will be properly pinned and
2533 // unpinned when the order gets changed through a profile / policy change.
2534 TEST_F(ChromeLauncherControllerImplTest,
2535 RestoreDefaultAndRunningV1AppsResyncOrder) {
2536 InitLauncherController();
2537
2538 syncer::SyncChangeList sync_list;
2539 InsertAddPinChange(&sync_list, 0, extension1_->id());
2540 InsertAddPinChange(&sync_list, 1, extension3_->id());
2541 SendPinChanges(sync_list, true);
2542
2543 // The shelf layout has always one static item at the beginning (App List).
2544 extension_service_->AddExtension(extension1_.get());
2545 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
2546 extension_service_->AddExtension(extension2_.get());
2547 // No new app icon will be generated.
2548 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
2549
2550 // Set the app status as running, which will add an unpinned item.
2551 launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_RUNNING);
2552 EXPECT_EQ("AppList, Chrome, App1, app2", GetPinnedAppStatus());
2553 extension_service_->AddExtension(extension3_.get());
2554 EXPECT_EQ("AppList, Chrome, App1, App3, app2", GetPinnedAppStatus());
2555
2556 // Now request to pin all items, which will pin the running unpinned items.
2557 syncer::SyncChangeList sync_list1;
2558 InsertAddPinChange(&sync_list1, 0, extension3_->id());
2559 InsertAddPinChange(&sync_list1, 1, extension2_->id());
2560 InsertAddPinChange(&sync_list1, 2, extension1_->id());
2561 SendPinChanges(sync_list1, true);
2562 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
2563
2564 // Removing the requirement for app 2 to be pinned should convert it back to
2565 // running but not pinned. It should move towards the end of the shelf, after
2566 // the pinned items, as determined by the |ShelfModel|'s weight system.
2567 syncer::SyncChangeList sync_list2;
2568 InsertAddPinChange(&sync_list2, 0, extension3_->id());
2569 InsertAddPinChange(&sync_list2, 1, extension1_->id());
2570 SendPinChanges(sync_list2, true);
2571 EXPECT_EQ("AppList, Chrome, App3, App1, app2", GetPinnedAppStatus());
2572
2573 // Removing an item should simply close it and everything should shift.
2574 SendPinChanges(syncer::SyncChangeList(), true);
2575 EXPECT_EQ("AppList, Chrome, App3, app2", GetPinnedAppStatus());
2576 }
2577
2578 // Check that a running unpinned V2 application will be properly pinned and
2579 // unpinned when the order gets changed through a profile / policy change.
2580 TEST_F(ChromeLauncherControllerImplTest,
2581 RestoreDefaultAndRunningV2AppsResyncOrder) {
2582 InitLauncherController();
2583 syncer::SyncChangeList sync_list0;
2584 InsertAddPinChange(&sync_list0, 0, extension1_->id());
2585 InsertAddPinChange(&sync_list0, 1, extension3_->id());
2586 SendPinChanges(sync_list0, true);
2587 // The shelf layout has always one static item at the beginning (app List).
2588 extension_service_->AddExtension(extension1_.get());
2589 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
2590 extension_service_->AddExtension(extension_platform_app_.get());
2591 // No new app icon will be generated.
2592 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
2593 // Add an unpinned but running V2 app.
2594 CreateRunningV2App(extension_platform_app_->id());
2595 EXPECT_EQ("AppList, Chrome, App1, *platform_app", GetPinnedAppStatus());
2596 extension_service_->AddExtension(extension3_.get());
2597 EXPECT_EQ("AppList, Chrome, App1, App3, *platform_app", GetPinnedAppStatus());
2598
2599 // Now request to pin all items, which should pin the running unpinned item.
2600 syncer::SyncChangeList sync_list1;
2601 InsertAddPinChange(&sync_list1, 0, extension3_->id());
2602 InsertAddPinChange(&sync_list1, 1, extension_platform_app_->id());
2603 InsertAddPinChange(&sync_list1, 2, extension1_->id());
2604 SendPinChanges(sync_list1, true);
2605 EXPECT_EQ("AppList, Chrome, App3, *Platform_App, App1", GetPinnedAppStatus());
2606
2607 // Removing the requirement for app 2 to be pinned should convert it back to
2608 // running but not pinned. It should move towards the end of the shelf, after
2609 // the pinned items, as determined by the |ShelfModel|'s weight system.
2610 syncer::SyncChangeList sync_list2;
2611 InsertAddPinChange(&sync_list2, 0, extension3_->id());
2612 InsertAddPinChange(&sync_list2, 1, extension1_->id());
2613 SendPinChanges(sync_list2, true);
2614 EXPECT_EQ("AppList, Chrome, App3, App1, *platform_app", GetPinnedAppStatus());
2615
2616 // Removing an item should simply close it and everything should shift.
2617 syncer::SyncChangeList sync_list3;
2618 InsertAddPinChange(&sync_list3, 0, extension3_->id());
2619 SendPinChanges(sync_list3, true);
2620 EXPECT_EQ("AppList, Chrome, App3, *platform_app", GetPinnedAppStatus());
2621 }
2622
2623 // Each user has a different set of applications pinned. Check that when
2624 // switching between the two users, the state gets properly set.
2625 TEST_F(ChromeLauncherControllerImplTest, UserSwitchIconRestore) {
2626 syncer::SyncChangeList user_a;
2627 syncer::SyncChangeList user_b;
2628
2629 SetUpMultiUserScenario(&user_a, &user_b);
2630
2631 // Show user 1.
2632 SendPinChanges(user_a, true);
2633 EXPECT_EQ("AppList, App1, App2, App3, *Platform_App, App4, App5, Chrome",
2634 GetPinnedAppStatus());
2635
2636 // Show user 2.
2637 SendPinChanges(user_b, true);
2638 EXPECT_EQ("AppList, App6, App7, App8, Chrome", GetPinnedAppStatus());
2639
2640 // Switch back to 1.
2641 SendPinChanges(user_a, true);
2642 EXPECT_EQ("AppList, App1, App2, App3, *Platform_App, App4, App5, Chrome",
2643 GetPinnedAppStatus());
2644
2645 // Switch back to 2.
2646 SendPinChanges(user_b, true);
2647 EXPECT_EQ("AppList, App6, App7, App8, Chrome", GetPinnedAppStatus());
2648 }
2649
2650 // Each user has a different set of applications pinned, and one user has an
2651 // application running. Check that when switching between the two users, the
2652 // state gets properly set.
2653 TEST_F(ChromeLauncherControllerImplTest,
2654 UserSwitchIconRestoreWithRunningV2App) {
2655 syncer::SyncChangeList user_a;
2656 syncer::SyncChangeList user_b;
2657
2658 SetUpMultiUserScenario(&user_a, &user_b);
2659
2660 // Run the platform (V2) app.
2661 CreateRunningV2App(extension_platform_app_->id());
2662
2663 // Show user 1.
2664 SendPinChanges(user_a, true);
2665 EXPECT_EQ("AppList, App1, App2, App3, *Platform_App, App4, App5, Chrome",
2666 GetPinnedAppStatus());
2667
2668 // Show user 2.
2669 SendPinChanges(user_b, true);
2670 EXPECT_EQ("AppList, App6, App7, App8, Chrome, *platform_app",
2671 GetPinnedAppStatus());
2672
2673 // Switch back to 1.
2674 SendPinChanges(user_a, true);
2675 EXPECT_EQ("AppList, App1, App2, App3, *Platform_App, App4, App5, Chrome",
2676 GetPinnedAppStatus());
2677
2678 // Switch back to 2.
2679 SendPinChanges(user_b, true);
2680 EXPECT_EQ("AppList, App6, App7, App8, Chrome, *platform_app",
2681 GetPinnedAppStatus());
2682 }
2683
2684 // Each user has a different set of applications pinned, and one user has an
2685 // application running. The chrome icon is not the last item in the list.
2686 // Check that when switching between the two users, the state gets properly set.
2687 // There was once a bug associated with this.
2688 TEST_F(ChromeLauncherControllerImplTest,
2689 UserSwitchIconRestoreWithRunningV2AppChromeInMiddle) {
2690 syncer::SyncChangeList user_a;
2691 syncer::SyncChangeList user_b;
2692 SetUpMultiUserScenario(&user_a, &user_b);
2693
2694 // Run the platform (V2) app.
2695 CreateRunningV2App(extension_platform_app_->id());
2696
2697 // Show user 1.
2698 SendPinChanges(user_a, true);
2699 SetShelfChromeIconIndex(5);
2700 EXPECT_EQ("AppList, App1, App2, App3, *Platform_App, App4, Chrome, App5",
2701 GetPinnedAppStatus());
2702
2703 // Show user 2.
2704 SendPinChanges(user_b, true);
2705 SetShelfChromeIconIndex(4);
2706 EXPECT_EQ("AppList, App6, App7, App8, Chrome, *platform_app",
2707 GetPinnedAppStatus());
2708
2709 // Switch back to 1.
2710 SendPinChanges(user_a, true);
2711 SetShelfChromeIconIndex(5);
2712 EXPECT_EQ("AppList, App1, App2, App3, *Platform_App, App4, Chrome, App5",
2713 GetPinnedAppStatus());
2714 }
2715
2716 TEST_F(ChromeLauncherControllerImplTest, Policy) {
2717 extension_service_->AddExtension(extension1_.get());
2718 extension_service_->AddExtension(extension3_.get());
2719
2720 InitLauncherController();
2721
2722 syncer::SyncChangeList sync_list;
2723 InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
2724 SendPinChanges(sync_list, true);
2725
2726 base::ListValue policy_value;
2727 InsertPrefValue(&policy_value, 0, extension1_->id());
2728 InsertPrefValue(&policy_value, 1, extension2_->id());
2729 profile()->GetTestingPrefService()->SetManagedPref(
2730 prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
2731
2732 // Only |extension1_| should get pinned. |extension2_| is specified but not
2733 // installed, and |extension3_| is part of the default set, but that shouldn't
2734 // take effect when the policy override is in place.
2735 ASSERT_EQ(3, model_->item_count());
2736 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
2737 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2738 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
2739 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
2740
2741 // Installing |extension2_| should add it to the launcher.
2742 extension_service_->AddExtension(extension2_.get());
2743 ASSERT_EQ(4, model_->item_count());
2744 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
2745 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
2746 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2747 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2748 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
2749
2750 // Removing |extension1_| from the policy should not be reflected in the
2751 // launcher and pin will exist.
2752 policy_value.Remove(0, NULL);
2753 profile()->GetTestingPrefService()->SetManagedPref(
2754 prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
2755 EXPECT_EQ(4, model_->item_count());
2756 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
2757 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
2758 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
2759 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
2760 }
2761
2762 TEST_F(ChromeLauncherControllerImplTest, UnpinWithUninstall) {
2763 extension_service_->AddExtension(extension3_.get());
2764 extension_service_->AddExtension(extension4_.get());
2765
2766 InitLauncherController();
2767
2768 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2769 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
2770
2771 extension_service_->UnloadExtension(extension3_->id(),
2772 UnloadedExtensionInfo::REASON_UNINSTALL);
2773
2774 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
2775 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
2776 }
2777
2778 TEST_F(ChromeLauncherControllerImplTest, SyncUpdates) {
2779 extension_service_->AddExtension(extension2_.get());
2780 extension_service_->AddExtension(extension3_.get());
2781 extension_service_->AddExtension(extension4_.get());
2782
2783 InitLauncherController();
2784
2785 syncer::SyncChangeList sync_list;
2786 InsertAddPinChange(&sync_list, 10, extension_misc::kChromeAppId);
2787 SendPinChanges(sync_list, true);
2788
2789 std::vector<std::string> expected_pinned_apps;
2790 std::vector<std::string> actual_pinned_apps;
2791 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2792 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2793
2794 // Unavailable extensions don't create launcher items.
2795 sync_list.clear();
2796 InsertAddPinChange(&sync_list, 0, extension1_->id());
2797 InsertAddPinChange(&sync_list, 1, extension2_->id());
2798 InsertAddPinChange(&sync_list, 3, extension4_->id());
2799 SendPinChanges(sync_list, false);
2800
2801 expected_pinned_apps.push_back(extension2_->id());
2802 expected_pinned_apps.push_back(extension4_->id());
2803 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2804 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2805
2806 sync_list.clear();
2807 InsertAddPinChange(&sync_list, 2, extension3_->id());
2808 SendPinChanges(sync_list, false);
2809 expected_pinned_apps.insert(expected_pinned_apps.begin() + 1,
2810 extension3_->id());
2811 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2812 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2813
2814 sync_list.clear();
2815 InsertUpdatePinChange(&sync_list, 0, extension4_->id());
2816 InsertUpdatePinChange(&sync_list, 1, extension3_->id());
2817 InsertUpdatePinChange(&sync_list, 2, extension2_->id());
2818 SendPinChanges(sync_list, false);
2819 std::reverse(expected_pinned_apps.begin(), expected_pinned_apps.end());
2820 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2821 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2822
2823 // Sending legacy sync change without pin info should not affect pin model.
2824 sync_list.clear();
2825 InsertLegacyPinChange(&sync_list, extension4_->id());
2826 SendPinChanges(sync_list, false);
2827 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2828 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2829
2830 sync_list.clear();
2831 InsertRemovePinChange(&sync_list, extension4_->id());
2832 SendPinChanges(sync_list, false);
2833 expected_pinned_apps.erase(expected_pinned_apps.begin());
2834 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2835 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2836
2837 sync_list.clear();
2838 InsertRemovePinChange(&sync_list, extension3_->id());
2839 InsertRemovePinChange(&sync_list, extension2_->id());
2840 SendPinChanges(sync_list, false);
2841 expected_pinned_apps.clear();
2842 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2843 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2844 }
2845
2846 TEST_F(ChromeLauncherControllerImplTest, ImportLegacyPin) {
2847 // Note extension3_ is actually Gmail app which is default pinned.
2848 extension_service_->AddExtension(extension3_.get());
2849 InitLauncherController();
2850
2851 // Default pins should contain Gmail. Pref is not syncing now.
2852 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
2853
2854 extension_service_->AddExtension(extension2_.get());
2855 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
2856
2857 // Initially pins are imported from legacy pref based model.
2858 base::ListValue value;
2859 InsertPrefValue(&value, 0, extension4_->id());
2860 InsertPrefValue(&value, 1, extension2_->id());
2861 InsertPrefValue(&value, 2, extension3_->id());
2862 StartPrefSyncServiceForPins(value);
2863
2864 // Imported pins contain App2. App2 should be added to pins now.
2865 EXPECT_EQ("AppList, Chrome, App2, App3", GetPinnedAppStatus());
2866
2867 // extension4_ is in the pin list.
2868 extension_service_->AddExtension(extension4_.get());
2869 // extension5_ is not in the pin list.
2870 extension_service_->AddExtension(extension5_.get());
2871 EXPECT_EQ("AppList, Chrome, App4, App2, App3", GetPinnedAppStatus());
2872
2873 // Apply app sync, unpin one app and pin new one.
2874 syncer::SyncChangeList sync_list;
2875 InsertAddPinChange(&sync_list, -1, extension3_->id());
2876 InsertAddPinChange(&sync_list, 3, extension5_->id());
2877 SendPinChanges(sync_list, false);
2878 EXPECT_EQ("AppList, Chrome, App4, App2, App5", GetPinnedAppStatus());
2879
2880 // At this point changing old pref based model does not affect pin model.
2881 InsertPrefValue(&value, 3, extension5_->id());
2882 StopPrefSyncService();
2883 StartPrefSyncServiceForPins(value);
2884 EXPECT_EQ("AppList, Chrome, App4, App2, App5", GetPinnedAppStatus());
2885
2886 // Next Chrome start should preserve pins.
2887 RecreateLauncherController()->Init();
2888 StopPrefSyncService();
2889 StartPrefSyncService(syncer::SyncDataList());
2890 EXPECT_EQ("AppList, Chrome, App4, App2, App5", GetPinnedAppStatus());
2891 }
2892
2893 TEST_F(ChromeLauncherControllerImplTest, PendingInsertionOrder) {
2894 extension_service_->AddExtension(extension1_.get());
2895 extension_service_->AddExtension(extension3_.get());
2896
2897 InitLauncherController();
2898
2899 syncer::SyncChangeList sync_list;
2900 InsertAddPinChange(&sync_list, 0, extension1_->id());
2901 InsertAddPinChange(&sync_list, 1, extension2_->id());
2902 InsertAddPinChange(&sync_list, 2, extension3_->id());
2903 SendPinChanges(sync_list, true);
2904
2905 std::vector<std::string> expected_pinned_apps;
2906 expected_pinned_apps.push_back(extension1_->id());
2907 expected_pinned_apps.push_back(extension3_->id());
2908 std::vector<std::string> actual_pinned_apps;
2909
2910 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2911 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2912
2913 // Install |extension2| and verify it shows up between the other two.
2914 extension_service_->AddExtension(extension2_.get());
2915 expected_pinned_apps.insert(expected_pinned_apps.begin() + 1,
2916 extension2_->id());
2917 GetPinnedAppIds(launcher_controller_, &actual_pinned_apps);
2918 EXPECT_EQ(expected_pinned_apps, actual_pinned_apps);
2919 }
2920
2921 // Ensure |controller| creates the expected menu items for the given shelf item.
2922 void CheckAppMenu(ChromeLauncherControllerImpl* controller,
2923 const ash::ShelfItem& item,
2924 size_t expected_item_count,
2925 base::string16 expected_item_titles[]) {
2926 ash::MenuItemList items = controller->GetAppMenuItemsForTesting(item);
2927 ASSERT_EQ(expected_item_count, items.size());
2928 for (size_t i = 0; i < expected_item_count; i++)
2929 EXPECT_EQ(expected_item_titles[i], items[i]->label);
2930 }
2931
2932 // Check that browsers get reflected correctly in the launcher menu.
2933 TEST_F(ChromeLauncherControllerImplTest, BrowserMenuGeneration) {
2934 EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
2935 chrome::NewTab(browser());
2936
2937 InitLauncherController();
2938
2939 // Check that the browser list is empty at this time.
2940 ash::ShelfItem item_browser;
2941 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2942 item_browser.id =
2943 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2944 CheckAppMenu(launcher_controller_, item_browser, 0, nullptr);
2945
2946 // Now make the created browser() visible by showing its browser window.
2947 browser()->window()->Show();
2948 base::string16 title1 = ASCIIToUTF16("Test1");
2949 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
2950 base::string16 one_menu_item[] = { title1 };
2951
2952 CheckAppMenu(launcher_controller_, item_browser, 1, one_menu_item);
2953
2954 // Create one more browser/window and check that one more was added.
2955 std::unique_ptr<Browser> browser2(
2956 CreateBrowserWithTestWindowForProfile(profile()));
2957 chrome::NewTab(browser2.get());
2958 browser2->window()->Show();
2959 base::string16 title2 = ASCIIToUTF16("Test2");
2960 NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
2961 title2);
2962
2963 // Check that the list contains now two entries - make furthermore sure that
2964 // the active item is the first entry.
2965 base::string16 two_menu_items[] = {title1, title2};
2966 CheckAppMenu(launcher_controller_, item_browser, 2, two_menu_items);
2967
2968 // Apparently we have to close all tabs we have.
2969 chrome::CloseTab(browser2.get());
2970 }
2971
2972 // Check the multi profile case where only user related browsers should show up.
2973 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
2974 BrowserMenuGenerationTwoUsers) {
2975 // Create a browser item in the LauncherController.
2976 InitLauncherController();
2977
2978 ash::ShelfItem item_browser;
2979 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2980 item_browser.id =
2981 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2982
2983 // Check that the menu is empty.
2984 chrome::NewTab(browser());
2985 CheckAppMenu(launcher_controller_, item_browser, 0, nullptr);
2986
2987 // Show the created |browser()| by showing its window.
2988 browser()->window()->Show();
2989 base::string16 title1 = ASCIIToUTF16("Test1");
2990 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
2991 base::string16 one_menu_item1[] = { title1 };
2992 CheckAppMenu(launcher_controller_, item_browser, 1, one_menu_item1);
2993
2994 // Create a browser for another user and check that it is not included in the
2995 // users running browser list.
2996 std::string user2 = "user2";
2997 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2998 const AccountId account_id2(
2999 multi_user_util::GetAccountIdFromProfile(profile2));
3000 std::unique_ptr<Browser> browser2(
3001 CreateBrowserAndTabWithProfile(profile2, user2, "http://test2"));
3002 base::string16 one_menu_item2[] = { ASCIIToUTF16(user2) };
3003 CheckAppMenu(launcher_controller_, item_browser, 1, one_menu_item1);
3004
3005 // Switch to the other user and make sure that only that browser window gets
3006 // shown.
3007 SwitchActiveUser(account_id2);
3008 CheckAppMenu(launcher_controller_, item_browser, 1, one_menu_item2);
3009
3010 // Transferred browsers of other users should not show up in the list.
3011 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
3012 browser()->window()->GetNativeWindow(), account_id2);
3013 CheckAppMenu(launcher_controller_, item_browser, 1, one_menu_item2);
3014
3015 chrome::CloseTab(browser2.get());
3016 }
3017
3018 // Check that V1 apps are correctly reflected in the launcher menu using the
3019 // refocus logic.
3020 // Note that the extension matching logic is tested by the extension system
3021 // and does not need a separate test here.
3022 TEST_F(ChromeLauncherControllerImplTest, V1AppMenuGeneration) {
3023 EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
3024 EXPECT_EQ(0, browser()->tab_strip_model()->count());
3025
3026 InitLauncherControllerWithBrowser();
3027
3028 // The model should only contain the browser shortcut and app list items.
3029 EXPECT_EQ(2, model_->item_count());
3030 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
3031
3032 // Installing |extension3_| adds it to the launcher.
3033 ash::ShelfID gmail_id = model_->next_id();
3034 extension_service_->AddExtension(extension3_.get());
3035 EXPECT_EQ(3, model_->item_count());
3036 int gmail_index = model_->ItemIndexByID(gmail_id);
3037 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[gmail_index].type);
3038 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
3039 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
3040
3041 // Check the menu content.
3042 ash::ShelfItem item_browser;
3043 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
3044 item_browser.id =
3045 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
3046
3047 ash::ShelfItem item_gmail;
3048 item_gmail.type = ash::TYPE_PINNED_APP;
3049 item_gmail.id = gmail_id;
3050 CheckAppMenu(launcher_controller_, item_gmail, 0, nullptr);
3051
3052 // Set the gmail URL to a new tab.
3053 base::string16 title1 = ASCIIToUTF16("Test1");
3054 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
3055
3056 base::string16 one_menu_item[] = { title1 };
3057 CheckAppMenu(launcher_controller_, item_gmail, 1, one_menu_item);
3058
3059 // Create one empty tab.
3060 chrome::NewTab(browser());
3061 base::string16 title2 = ASCIIToUTF16("Test2");
3062 NavigateAndCommitActiveTabWithTitle(
3063 browser(),
3064 GURL("https://bla"),
3065 title2);
3066
3067 // and another one with another gmail instance.
3068 chrome::NewTab(browser());
3069 base::string16 title3 = ASCIIToUTF16("Test3");
3070 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3);
3071 base::string16 two_menu_items[] = {title1, title3};
3072 CheckAppMenu(launcher_controller_, item_gmail, 2, two_menu_items);
3073
3074 // Even though the item is in the V1 app list, it should also be in the
3075 // browser list.
3076 base::string16 browser_menu_item[] = {title3};
3077 CheckAppMenu(launcher_controller_, item_browser, 1, browser_menu_item);
3078
3079 // Test that closing of (all) the item(s) does work (and all menus get
3080 // updated properly).
3081 launcher_controller_->Close(item_gmail.id);
3082
3083 CheckAppMenu(launcher_controller_, item_gmail, 0, nullptr);
3084 base::string16 browser_menu_item2[] = { title2 };
3085 CheckAppMenu(launcher_controller_, item_browser, 1, browser_menu_item2);
3086 }
3087
3088 // Check the multi profile case where only user related apps should show up.
3089 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
3090 V1AppMenuGenerationTwoUsers) {
3091 // Create a browser item in the LauncherController.
3092 InitLauncherController();
3093 chrome::NewTab(browser());
3094
3095 // Installing |extension3_| adds it to the launcher.
3096 ash::ShelfID gmail_id = model_->next_id();
3097 extension_service_->AddExtension(extension3_.get());
3098 EXPECT_EQ(3, model_->item_count());
3099 int gmail_index = model_->ItemIndexByID(gmail_id);
3100 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[gmail_index].type);
3101 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
3102 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
3103
3104 // Check the menu content.
3105 ash::ShelfItem item_browser;
3106 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
3107 item_browser.id =
3108 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
3109
3110 ash::ShelfItem item_gmail;
3111 item_gmail.type = ash::TYPE_PINNED_APP;
3112 item_gmail.id = gmail_id;
3113 CheckAppMenu(launcher_controller_, item_gmail, 0, nullptr);
3114
3115 // Set the gmail URL to a new tab.
3116 base::string16 title1 = ASCIIToUTF16("Test1");
3117 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
3118
3119 base::string16 one_menu_item[] = { title1 };
3120 CheckAppMenu(launcher_controller_, item_gmail, 1, one_menu_item);
3121
3122 // Create a second profile and switch to that user.
3123 std::string user2 = "user2";
3124 TestingProfile* profile2 = CreateMultiUserProfile(user2);
3125 const AccountId account_id2(
3126 multi_user_util::GetAccountIdFromProfile(profile2));
3127 SwitchActiveUser(account_id2);
3128
3129 // No item should have content yet.
3130 CheckAppMenu(launcher_controller_, item_browser, 0, nullptr);
3131 CheckAppMenu(launcher_controller_, item_gmail, 0, nullptr);
3132
3133 // Transfer the browser of the first user - it should still not show up.
3134 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
3135 browser()->window()->GetNativeWindow(), account_id2);
3136
3137 CheckAppMenu(launcher_controller_, item_browser, 0, nullptr);
3138 CheckAppMenu(launcher_controller_, item_gmail, 0, nullptr);
3139 }
3140
3141 // Check that V2 applications are creating items properly in the launcher when
3142 // instantiated by the current user.
3143 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
3144 V2AppHandlingTwoUsers) {
3145 InitLauncherController();
3146 // Create a profile for our second user (will be destroyed by the framework).
3147 TestingProfile* profile2 = CreateMultiUserProfile("user2");
3148 const AccountId account_id(
3149 multi_user_util::GetAccountIdFromProfile(profile()));
3150 const AccountId account_id2(
3151 multi_user_util::GetAccountIdFromProfile(profile2));
3152 // Check that there is a browser and a app launcher.
3153 EXPECT_EQ(2, model_->item_count());
3154
3155 // Add a v2 app.
3156 V2App v2_app(profile(), extension1_.get());
3157 EXPECT_EQ(3, model_->item_count());
3158
3159 // After switching users the item should go away.
3160 SwitchActiveUser(account_id2);
3161 EXPECT_EQ(2, model_->item_count());
3162
3163 // And it should come back when switching back.
3164 SwitchActiveUser(account_id);
3165 EXPECT_EQ(3, model_->item_count());
3166 }
3167
3168 // Check that V2 applications are creating items properly in edge cases:
3169 // a background user creates a V2 app, gets active and inactive again and then
3170 // deletes the app.
3171 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
3172 V2AppHandlingTwoUsersEdgeCases) {
3173 InitLauncherController();
3174 // Create a profile for our second user (will be destroyed by the framework).
3175 TestingProfile* profile2 = CreateMultiUserProfile("user2");
3176 const AccountId account_id(
3177 multi_user_util::GetAccountIdFromProfile(profile()));
3178 const AccountId account_id2(
3179 multi_user_util::GetAccountIdFromProfile(profile2));
3180 // Check that there is a browser and a app launcher.
3181 EXPECT_EQ(2, model_->item_count());
3182
3183 // Switch to an inactive user.
3184 SwitchActiveUser(account_id2);
3185 EXPECT_EQ(2, model_->item_count());
3186
3187 // Add the v2 app to the inactive user and check that no item was added to
3188 // the launcher.
3189 {
3190 V2App v2_app(profile(), extension1_.get());
3191 EXPECT_EQ(2, model_->item_count());
3192
3193 // Switch to the primary user and check that the item is shown.
3194 SwitchActiveUser(account_id);
3195 EXPECT_EQ(3, model_->item_count());
3196
3197 // Switch to the second user and check that the item goes away - even if the
3198 // item gets closed.
3199 SwitchActiveUser(account_id2);
3200 EXPECT_EQ(2, model_->item_count());
3201 }
3202
3203 // After the application was killed there should be still 2 items.
3204 EXPECT_EQ(2, model_->item_count());
3205
3206 // Switching then back to the default user should not show the additional item
3207 // anymore.
3208 SwitchActiveUser(account_id);
3209 EXPECT_EQ(2, model_->item_count());
3210 }
3211
3212 // Check that V2 applications will be made visible on the target desktop if
3213 // another window of the same type got previously teleported there.
3214 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
3215 V2AppFollowsTeleportedWindow) {
3216 InitLauncherController();
3217 chrome::MultiUserWindowManager* manager =
3218 chrome::MultiUserWindowManager::GetInstance();
3219
3220 // Create and add three users / profiles, and go to #1's desktop.
3221 TestingProfile* profile1 = CreateMultiUserProfile("user-1");
3222 TestingProfile* profile2 = CreateMultiUserProfile("user-2");
3223 TestingProfile* profile3 = CreateMultiUserProfile("user-3");
3224 const AccountId account_id1(
3225 multi_user_util::GetAccountIdFromProfile(profile1));
3226 const AccountId account_id2(
3227 multi_user_util::GetAccountIdFromProfile(profile2));
3228 const AccountId account_id3(
3229 multi_user_util::GetAccountIdFromProfile(profile3));
3230 SwitchActiveUser(account_id1);
3231
3232 // A v2 app for user #1 should be shown first and get hidden when switching to
3233 // desktop #2.
3234 V2App v2_app_1(profile1, extension1_.get());
3235 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3236 SwitchActiveUser(account_id2);
3237 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3238
3239 // Add a v2 app for user #1 while on desktop #2 should not be shown.
3240 V2App v2_app_2(profile1, extension1_.get());
3241 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3242 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3243
3244 // Teleport the app from user #1 to the desktop #2 should show it.
3245 manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(), account_id2);
3246 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3247 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3248
3249 // Creating a new application for user #1 on desktop #2 should teleport it
3250 // there automatically.
3251 V2App v2_app_3(profile1, extension1_.get());
3252 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3253 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3254 EXPECT_TRUE(v2_app_3.window()->GetNativeWindow()->IsVisible());
3255
3256 // Switching back to desktop#1 and creating an app for user #1 should move
3257 // the app on desktop #1.
3258 SwitchActiveUser(account_id1);
3259 V2App v2_app_4(profile1, extension1_.get());
3260 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3261 EXPECT_TRUE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3262 EXPECT_FALSE(v2_app_3.window()->GetNativeWindow()->IsVisible());
3263 EXPECT_TRUE(v2_app_4.window()->GetNativeWindow()->IsVisible());
3264
3265 // Switching to desktop #3 and creating an app for user #1 should place it on
3266 // that user's desktop (#1).
3267 SwitchActiveUser(account_id3);
3268 V2App v2_app_5(profile1, extension1_.get());
3269 EXPECT_FALSE(v2_app_5.window()->GetNativeWindow()->IsVisible());
3270 SwitchActiveUser(account_id1);
3271 EXPECT_TRUE(v2_app_5.window()->GetNativeWindow()->IsVisible());
3272
3273 // Switching to desktop #2, hiding the app window and creating an app should
3274 // teleport there automatically.
3275 SwitchActiveUser(account_id2);
3276 v2_app_1.window()->Hide();
3277 V2App v2_app_6(profile1, extension1_.get());
3278 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
3279 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
3280 EXPECT_TRUE(v2_app_6.window()->GetNativeWindow()->IsVisible());
3281 }
3282
3283 // Check that V2 applications hide correctly on the shelf when the app window
3284 // is hidden.
3285 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerImplTest,
3286 V2AppHiddenWindows) {
3287 InitLauncherController();
3288
3289 TestingProfile* profile2 = CreateMultiUserProfile("user-2");
3290 const AccountId account_id(
3291 multi_user_util::GetAccountIdFromProfile(profile()));
3292 const AccountId account_id2(
3293 multi_user_util::GetAccountIdFromProfile(profile2));
3294 SwitchActiveUser(account_id);
3295 EXPECT_EQ(2, model_->item_count());
3296
3297 V2App v2_app_1(profile(), extension1_.get());
3298 EXPECT_EQ(3, model_->item_count());
3299 {
3300 // Hide and show the app.
3301 v2_app_1.window()->Hide();
3302 EXPECT_EQ(2, model_->item_count());
3303
3304 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3305 EXPECT_EQ(3, model_->item_count());
3306 }
3307 {
3308 // Switch user, hide and show the app and switch back.
3309 SwitchActiveUser(account_id2);
3310 EXPECT_EQ(2, model_->item_count());
3311
3312 v2_app_1.window()->Hide();
3313 EXPECT_EQ(2, model_->item_count());
3314
3315 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3316 EXPECT_EQ(2, model_->item_count());
3317
3318 SwitchActiveUser(account_id);
3319 EXPECT_EQ(3, model_->item_count());
3320 }
3321 {
3322 // Switch user, hide the app, switch back and then show it again.
3323 SwitchActiveUser(account_id2);
3324 EXPECT_EQ(2, model_->item_count());
3325
3326 v2_app_1.window()->Hide();
3327 EXPECT_EQ(2, model_->item_count());
3328
3329 SwitchActiveUser(account_id);
3330 // The following expectation does not work in current impl. It was working
3331 // before because MultiUserWindowManagerChromeOS is not attached to user
3332 // associated with profile() hence not actually handling windows for the
3333 // user. It is a real bug. See http://crbug.com/693634
3334 // EXPECT_EQ(2, model_->item_count());
3335
3336 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3337 EXPECT_EQ(3, model_->item_count());
3338 }
3339 {
3340 // Create a second app, hide and show it and then hide both apps.
3341 V2App v2_app_2(profile(), extension1_.get());
3342 EXPECT_EQ(3, model_->item_count());
3343
3344 v2_app_2.window()->Hide();
3345 EXPECT_EQ(3, model_->item_count());
3346
3347 v2_app_2.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
3348 EXPECT_EQ(3, model_->item_count());
3349
3350 v2_app_1.window()->Hide();
3351 v2_app_2.window()->Hide();
3352 EXPECT_EQ(2, model_->item_count());
3353 }
3354 }
3355
3356 // Checks that the generated menu list properly activates items.
3357 TEST_F(ChromeLauncherControllerImplTest, V1AppMenuExecution) {
3358 InitLauncherControllerWithBrowser();
3359
3360 // Add |extension3_| to the launcher and add two items.
3361 GURL gmail = GURL("https://mail.google.com/mail/u");
3362 ash::ShelfID gmail_id = model_->next_id();
3363 extension_service_->AddExtension(extension3_.get());
3364 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
3365 base::string16 title1 = ASCIIToUTF16("Test1");
3366 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
3367 chrome::NewTab(browser());
3368 base::string16 title2 = ASCIIToUTF16("Test2");
3369 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
3370
3371 // Check that the menu is properly set.
3372 ash::ShelfItem item_gmail;
3373 item_gmail.type = ash::TYPE_PINNED_APP;
3374 item_gmail.id = gmail_id;
3375 base::string16 two_menu_items[] = {title1, title2};
3376 CheckAppMenu(launcher_controller_, item_gmail, 2, two_menu_items);
3377 ash::ShelfItemDelegate* item_delegate =
3378 model_->GetShelfItemDelegate(gmail_id);
3379 ASSERT_TRUE(item_delegate);
3380 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
3381 // Execute the second item in the menu, after the title and two separators,
3382 // this shouldn't do anything since that item is already the active tab.
3383 {
3384 ash::ShelfApplicationMenuModel menu(
3385 base::string16(),
3386 launcher_controller_->GetAppMenuItemsForTesting(item_gmail),
3387 item_delegate);
3388 menu.ActivatedAt(4);
3389 }
3390 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
3391
3392 // Execute the first item in the menu, after the title and two separators,
3393 // this should activate the other tab.
3394 {
3395 ash::ShelfApplicationMenuModel menu(
3396 base::string16(),
3397 launcher_controller_->GetAppMenuItemsForTesting(item_gmail),
3398 item_delegate);
3399 menu.ActivatedAt(3);
3400 }
3401 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
3402 }
3403
3404 // Checks that the generated menu list properly deletes items.
3405 TEST_F(ChromeLauncherControllerImplTest, V1AppMenuDeletionExecution) {
3406 InitLauncherControllerWithBrowser();
3407
3408 // Add |extension3_| to the launcher and add two items.
3409 GURL gmail = GURL("https://mail.google.com/mail/u");
3410 ash::ShelfID gmail_id = model_->next_id();
3411 extension_service_->AddExtension(extension3_.get());
3412 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
3413 base::string16 title1 = ASCIIToUTF16("Test1");
3414 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
3415 chrome::NewTab(browser());
3416 base::string16 title2 = ASCIIToUTF16("Test2");
3417 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
3418
3419 // Check that the menu is properly set.
3420 ash::ShelfItem item_gmail;
3421 item_gmail.type = ash::TYPE_PINNED_APP;
3422 item_gmail.id = gmail_id;
3423 base::string16 two_menu_items[] = {title1, title2};
3424 CheckAppMenu(launcher_controller_, item_gmail, 2, two_menu_items);
3425
3426 ash::ShelfItemDelegate* item_delegate =
3427 model_->GetShelfItemDelegate(gmail_id);
3428 ASSERT_TRUE(item_delegate);
3429 int tabs = browser()->tab_strip_model()->count();
3430 // Activate the proper tab through the menu item.
3431 {
3432 ash::MenuItemList items =
3433 launcher_controller_->GetAppMenuItemsForTesting(item_gmail);
3434 item_delegate->ExecuteCommand(items[1]->command_id, ui::EF_NONE);
3435 EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
3436 }
3437
3438 // Delete one tab through the menu item.
3439 {
3440 ash::MenuItemList items =
3441 launcher_controller_->GetAppMenuItemsForTesting(item_gmail);
3442 item_delegate->ExecuteCommand(items[1]->command_id, ui::EF_SHIFT_DOWN);
3443 EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
3444 }
3445 }
3446
3447 // Tests that panels create launcher items correctly
3448 TEST_F(ChromeLauncherControllerImplTest, AppPanels) {
3449 InitLauncherController();
3450 model_observer_->clear_counts();
3451 const std::string app_id = extension1_->id();
3452
3453 // app_icon_loader is owned by ChromeLauncherControllerImpl.
3454 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl();
3455 app_icon_loader->AddSupportedApp(app_id);
3456 SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader));
3457
3458 // Make an app panel; the ShelfItem is added by ash::ShelfWindowWatcher.
3459 std::unique_ptr<V2App> app_panel1 = base::MakeUnique<V2App>(
3460 profile(), extension1_.get(), extensions::AppWindow::WINDOW_TYPE_PANEL);
3461 EXPECT_TRUE(app_panel1->window()->GetNativeWindow()->IsVisible());
3462 int panel_index = model_observer_->last_index();
3463 EXPECT_EQ(1, model_observer_->added());
3464 EXPECT_EQ(1, app_icon_loader->fetch_count());
3465 model_observer_->clear_counts();
3466
3467 // App panels should have a separate identifier than the app id
3468 EXPECT_EQ(ash::kInvalidShelfID,
3469 launcher_controller_->GetShelfIDForAppID(app_id));
3470
3471 // Setting the app image should not change the panel, which has a window icon.
3472 gfx::ImageSkia image;
3473 launcher_controller_->OnAppImageUpdated(app_id, image);
3474 EXPECT_EQ(0, model_observer_->changed());
3475 model_observer_->clear_counts();
3476
3477 // Make a second app panel and verify that it gets the same index as the first
3478 // panel, being added to the left of the existing panel.
3479 std::unique_ptr<V2App> app_panel2 = base::MakeUnique<V2App>(
3480 profile(), extension2_.get(), extensions::AppWindow::WINDOW_TYPE_PANEL);
3481 EXPECT_EQ(panel_index, model_observer_->last_index());
3482 EXPECT_EQ(1, model_observer_->added());
3483 model_observer_->clear_counts();
3484
3485 app_panel1.reset();
3486 app_panel2.reset();
3487 EXPECT_EQ(2, model_observer_->removed());
3488 }
3489
3490 // Tests that the Gmail extension matches more than the app itself claims with
3491 // the manifest file.
3492 TEST_F(ChromeLauncherControllerImplTest, GmailMatching) {
3493 InitLauncherControllerWithBrowser();
3494
3495 // Create a Gmail browser tab.
3496 chrome::NewTab(browser());
3497 base::string16 title = ASCIIToUTF16("Test");
3498 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title);
3499 content::WebContents* content =
3500 browser()->tab_strip_model()->GetActiveWebContents();
3501
3502 // Check that the launcher controller does not recognize the running app.
3503 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
3504
3505 // Installing |extension3_| adds it to the launcher.
3506 ash::ShelfID gmail_id = model_->next_id();
3507 extension_service_->AddExtension(extension3_.get());
3508 EXPECT_EQ(3, model_->item_count());
3509 int gmail_index = model_->ItemIndexByID(gmail_id);
3510 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[gmail_index].type);
3511 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
3512
3513 // Check that it is now handled.
3514 EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
3515
3516 // Check also that the app has detected that properly.
3517 ash::ShelfItem item_gmail;
3518 item_gmail.type = ash::TYPE_PINNED_APP;
3519 item_gmail.id = gmail_id;
3520 EXPECT_EQ(1U,
3521 launcher_controller_->GetAppMenuItemsForTesting(item_gmail).size());
3522 }
3523
3524 // Tests that the Gmail extension does not match the offline verison.
3525 TEST_F(ChromeLauncherControllerImplTest, GmailOfflineMatching) {
3526 InitLauncherControllerWithBrowser();
3527
3528 // Create a Gmail browser tab.
3529 chrome::NewTab(browser());
3530 base::string16 title = ASCIIToUTF16("Test");
3531 NavigateAndCommitActiveTabWithTitle(browser(),
3532 GURL(offline_gmail_url),
3533 title);
3534 content::WebContents* content =
3535 browser()->tab_strip_model()->GetActiveWebContents();
3536
3537 // Installing |extension3_| adds it to the launcher.
3538 ash::ShelfID gmail_id = model_->next_id();
3539 extension_service_->AddExtension(extension3_.get());
3540 EXPECT_EQ(3, model_->item_count());
3541 int gmail_index = model_->ItemIndexByID(gmail_id);
3542 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[gmail_index].type);
3543 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
3544
3545 // The content should not be able to be handled by the app.
3546 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
3547 }
3548
3549 // Verify that the launcher item positions are persisted and restored.
3550 TEST_F(ChromeLauncherControllerImplTest, PersistLauncherItemPositions) {
3551 InitLauncherController();
3552
3553 TestLauncherControllerHelper* helper = new TestLauncherControllerHelper;
3554 SetLauncherControllerHelper(helper);
3555
3556 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
3557 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
3558
3559 TabStripModel* tab_strip_model = browser()->tab_strip_model();
3560 EXPECT_EQ(0, tab_strip_model->count());
3561 chrome::NewTab(browser());
3562 chrome::NewTab(browser());
3563 EXPECT_EQ(2, tab_strip_model->count());
3564 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
3565 helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
3566
3567 EXPECT_FALSE(launcher_controller_->IsAppPinned("1"));
3568 launcher_controller_->PinAppWithID("1");
3569 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
3570 launcher_controller_->PinAppWithID("2");
3571
3572 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
3573 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
3574 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
3575 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[3].type);
3576
3577 // Move browser shortcut item from index 1 to index 3.
3578 model_->Move(1, 3);
3579 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
3580 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
3581 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
3582 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
3583
3584 RecreateLauncherController();
3585 helper = new TestLauncherControllerHelper(profile());
3586 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
3587 helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
3588 SetLauncherControllerHelper(helper);
3589 launcher_controller_->Init();
3590
3591 // Check ShelfItems are restored after resetting ChromeLauncherControllerImpl.
3592 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
3593 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
3594 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
3595 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
3596 }
3597
3598 // Verifies pinned apps are persisted and restored.
3599 TEST_F(ChromeLauncherControllerImplTest, PersistPinned) {
3600 InitLauncherControllerWithBrowser();
3601 size_t initial_size = model_->items().size();
3602
3603 TabStripModel* tab_strip_model = browser()->tab_strip_model();
3604 EXPECT_EQ(1, tab_strip_model->count());
3605
3606 TestLauncherControllerHelper* helper = new TestLauncherControllerHelper;
3607 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
3608 SetLauncherControllerHelper(helper);
3609
3610 // app_icon_loader is owned by ChromeLauncherControllerImpl.
3611 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl;
3612 app_icon_loader->AddSupportedApp("1");
3613 SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader));
3614 EXPECT_EQ(0, app_icon_loader->fetch_count());
3615
3616 launcher_controller_->PinAppWithID("1");
3617 ash::ShelfID id = launcher_controller_->GetShelfIDForAppID("1");
3618 int app_index = model_->ItemIndexByID(id);
3619 EXPECT_EQ(1, app_icon_loader->fetch_count());
3620 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[app_index].type);
3621 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
3622 EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
3623 EXPECT_EQ(initial_size + 1, model_->items().size());
3624
3625 RecreateLauncherController();
3626 helper = new TestLauncherControllerHelper(profile());
3627 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
3628 SetLauncherControllerHelper(helper);
3629 // app_icon_loader is owned by ChromeLauncherControllerImpl.
3630 app_icon_loader = new TestAppIconLoaderImpl;
3631 app_icon_loader->AddSupportedApp("1");
3632 SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader));
3633 launcher_controller_->Init();
3634
3635 EXPECT_EQ(1, app_icon_loader->fetch_count());
3636 ASSERT_EQ(initial_size + 1, model_->items().size());
3637 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
3638 EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
3639 EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[app_index].type);
3640
3641 launcher_controller_->UnpinAppWithID("1");
3642 ASSERT_EQ(initial_size, model_->items().size());
3643 }
3644
3645 TEST_F(ChromeLauncherControllerImplTest, MultipleAppIconLoaders) {
3646 InitLauncherControllerWithBrowser();
3647
3648 const std::string app_id1 = extension1_->id();
3649 const std::string app_id2 = extension2_->id();
3650 const std::string app_id3 = extension3_->id();
3651 // app_icon_loader1 and app_icon_loader2 are owned by
3652 // ChromeLauncherControllerImpl.
3653 TestAppIconLoaderImpl* app_icon_loader1 = new TestAppIconLoaderImpl();
3654 TestAppIconLoaderImpl* app_icon_loader2 = new TestAppIconLoaderImpl();
3655 app_icon_loader1->AddSupportedApp(app_id1);
3656 app_icon_loader2->AddSupportedApp(app_id2);
3657 SetAppIconLoaders(std::unique_ptr<AppIconLoader>(app_icon_loader1),
3658 std::unique_ptr<AppIconLoader>(app_icon_loader2));
3659
3660 const ash::ShelfID shelfId3 = launcher_controller_->CreateAppLauncherItem(
3661 base::MakeUnique<ExtensionAppWindowLauncherItemController>(
3662 ash::AppLaunchId(app_id3)),
3663 ash::STATUS_RUNNING);
3664 EXPECT_EQ(0, app_icon_loader1->fetch_count());
3665 EXPECT_EQ(0, app_icon_loader1->clear_count());
3666 EXPECT_EQ(0, app_icon_loader2->fetch_count());
3667 EXPECT_EQ(0, app_icon_loader2->clear_count());
3668
3669 const ash::ShelfID shelfId2 = launcher_controller_->CreateAppLauncherItem(
3670 base::MakeUnique<ExtensionAppWindowLauncherItemController>(
3671 ash::AppLaunchId(app_id2)),
3672 ash::STATUS_RUNNING);
3673 EXPECT_EQ(0, app_icon_loader1->fetch_count());
3674 EXPECT_EQ(0, app_icon_loader1->clear_count());
3675 EXPECT_EQ(1, app_icon_loader2->fetch_count());
3676 EXPECT_EQ(0, app_icon_loader2->clear_count());
3677
3678 const ash::ShelfID shelfId1 = launcher_controller_->CreateAppLauncherItem(
3679 base::MakeUnique<ExtensionAppWindowLauncherItemController>(
3680 ash::AppLaunchId(app_id1)),
3681 ash::STATUS_RUNNING);
3682 EXPECT_EQ(1, app_icon_loader1->fetch_count());
3683 EXPECT_EQ(0, app_icon_loader1->clear_count());
3684 EXPECT_EQ(1, app_icon_loader2->fetch_count());
3685 EXPECT_EQ(0, app_icon_loader2->clear_count());
3686
3687 launcher_controller_->CloseLauncherItem(shelfId1);
3688 EXPECT_EQ(1, app_icon_loader1->fetch_count());
3689 EXPECT_EQ(1, app_icon_loader1->clear_count());
3690 EXPECT_EQ(1, app_icon_loader2->fetch_count());
3691 EXPECT_EQ(0, app_icon_loader2->clear_count());
3692
3693 launcher_controller_->CloseLauncherItem(shelfId2);
3694 EXPECT_EQ(1, app_icon_loader1->fetch_count());
3695 EXPECT_EQ(1, app_icon_loader1->clear_count());
3696 EXPECT_EQ(1, app_icon_loader2->fetch_count());
3697 EXPECT_EQ(1, app_icon_loader2->clear_count());
3698
3699 launcher_controller_->CloseLauncherItem(shelfId3);
3700 EXPECT_EQ(1, app_icon_loader1->fetch_count());
3701 EXPECT_EQ(1, app_icon_loader1->clear_count());
3702 EXPECT_EQ(1, app_icon_loader2->fetch_count());
3703 EXPECT_EQ(1, app_icon_loader2->clear_count());
3704 }
3705
3706 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcAppPinPolicy) {
3707 InitLauncherControllerWithBrowser();
3708 arc::mojom::AppInfo appinfo = CreateAppInfo(
3709 "Some App", "SomeActivity", "com.example.app", OrientationLock::NONE);
3710 const std::string app_id = AddArcAppAndShortcut(appinfo);
3711
3712 // Set policy, that makes pins ARC app. Unlike native extension, for ARC app
3713 // package_name (not hash) specified as id. In this test we check that
3714 // by hash we can determine that appropriate package was set by policy.
3715 base::ListValue policy_value;
3716 InsertPrefValue(&policy_value, 0, appinfo.package_name);
3717 profile()->GetTestingPrefService()->SetManagedPref(
3718 prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
3719
3720 EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id));
3721 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED,
3722 GetPinnableForAppID(app_id, profile()));
3723 }
3724
3725 TEST_P(ChromeLauncherControllerImplWithArcTest, ArcManaged) {
3726 // TODO(victorhsieh): Implement opt-in and opt-out.
3727 if (arc::ShouldArcAlwaysStart())
3728 return;
3729
3730 extension_service_->AddExtension(arc_support_host_.get());
3731 // Test enables ARC, so turn it off for initial values.
3732 EnablePlayStore(false);
3733
3734 InitLauncherController();
3735
3736 // To prevent import legacy pins each time.
3737 // Initially pins are imported from legacy pref based model.
3738 StartPrefSyncService(syncer::SyncDataList());
3739
3740 // Initial run, ARC is not managed and disabled, Play Store pin should be
3741 // available.
3742 ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
3743 "AppList, Chrome, Play Store");
3744
3745 // ARC is managed and enabled, Play Store pin should be available.
3746 // Note: NEGOTIATING_TERMS_OF_SERVICE here means that opt-in flow starts.
3747 profile()->GetTestingPrefService()->SetManagedPref(
3748 prefs::kArcEnabled, base::MakeUnique<base::Value>(true));
3749 base::RunLoop().RunUntilIdle();
3750 ValidateArcState(true, true,
3751 arc::ArcSessionManager::State::NEGOTIATING_TERMS_OF_SERVICE,
3752 "AppList, Chrome, Play Store");
3753
3754 // ARC is managed and disabled, Play Store pin should not be available.
3755 profile()->GetTestingPrefService()->SetManagedPref(
3756 prefs::kArcEnabled, base::MakeUnique<base::Value>(false));
3757 base::RunLoop().RunUntilIdle();
3758 ValidateArcState(false, true, arc::ArcSessionManager::State::STOPPED,
3759 "AppList, Chrome");
3760
3761 // ARC is not managed and disabled, Play Store pin should be available.
3762 profile()->GetTestingPrefService()->RemoveManagedPref(prefs::kArcEnabled);
3763 base::RunLoop().RunUntilIdle();
3764 ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
3765 "AppList, Chrome, Play Store");
3766
3767 // ARC is not managed and enabled, Play Store pin should be available.
3768 EnablePlayStore(true);
3769 ValidateArcState(true, false,
3770 arc::ArcSessionManager::State::NEGOTIATING_TERMS_OF_SERVICE,
3771 "AppList, Chrome, Play Store");
3772
3773 // User disables ARC. ARC is not managed and disabled, Play Store pin should
3774 // be automatically removed.
3775 EnablePlayStore(false);
3776 ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
3777 "AppList, Chrome");
3778
3779 // Even if re-enable it again, Play Store pin does not appear automatically.
3780 EnablePlayStore(true);
3781 ValidateArcState(true, false,
3782 arc::ArcSessionManager::State::NEGOTIATING_TERMS_OF_SERVICE,
3783 "AppList, Chrome");
3784 }
3785
3786 // Test the application menu of a shelf item with multiple ARC windows.
3787 TEST_P(ChromeLauncherControllerImplWithArcTest, ShelfItemWithMultipleWindows) {
3788 InitLauncherControllerWithBrowser();
3789
3790 arc::mojom::AppInfo appinfo =
3791 CreateAppInfo("Test1", "test", "com.example.app", OrientationLock::NONE);
3792 AddArcAppAndShortcut(appinfo);
3793
3794 // Widgets will be deleted by the system.
3795 NotifyOnTaskCreated(appinfo, 1 /* task_id */);
3796 views::Widget* window1 = CreateArcWindow("org.chromium.arc.1");
3797 ASSERT_TRUE(window1);
3798 EXPECT_TRUE(window1->IsActive());
3799
3800 NotifyOnTaskCreated(appinfo, 2 /* task_id */);
3801 views::Widget* window2 = CreateArcWindow("org.chromium.arc.2");
3802 ASSERT_TRUE(window2);
3803
3804 EXPECT_FALSE(window1->IsActive());
3805 EXPECT_TRUE(window2->IsActive());
3806
3807 const std::string app_id = ArcAppTest::GetAppId(appinfo);
3808
3809 const ash::ShelfID shelf_id =
3810 launcher_controller_->GetShelfIDForAppID(app_id);
3811 ash::ShelfItemDelegate* item_delegate =
3812 model_->GetShelfItemDelegate(shelf_id);
3813 ASSERT_TRUE(item_delegate);
3814
3815 // Selecting the item will show its application menu. It does not change the
3816 // active window.
3817 SelectItem(item_delegate);
3818 EXPECT_FALSE(window1->IsActive());
3819 EXPECT_TRUE(window2->IsActive());
3820
3821 // Command ids are just app window indices. Note, apps are registered in
3822 // opposite order. Last created goes in front.
3823 ash::MenuItemList items = item_delegate->GetAppMenuItems(0);
3824 ASSERT_EQ(items.size(), 2U);
3825 EXPECT_EQ(items[0]->command_id, 0U);
3826 EXPECT_EQ(items[1]->command_id, 1U);
3827
3828 // Execute command to activate first window.
3829 item_delegate->ExecuteCommand(items[1]->command_id, 0);
3830 EXPECT_TRUE(window1->IsActive());
3831 EXPECT_FALSE(window2->IsActive());
3832
3833 // Selecting the item will show its application menu. It does not change the
3834 // active window.
3835 SelectItem(item_delegate);
3836 EXPECT_TRUE(window1->IsActive());
3837 EXPECT_FALSE(window2->IsActive());
3838
3839 // Execute command to activate second window.
3840 item_delegate->ExecuteCommand(items[0]->command_id, 0);
3841 EXPECT_FALSE(window1->IsActive());
3842 EXPECT_TRUE(window2->IsActive());
3843 }
3844
3845 namespace {
3846
3847 class ChromeLauncherControllerOrientationTest
3848 : public ChromeLauncherControllerImplWithArcTest {
3849 public:
3850 ChromeLauncherControllerOrientationTest() {}
3851 ~ChromeLauncherControllerOrientationTest() override {}
3852
3853 protected:
3854 void InitApps() {
3855 appinfo_none_ =
3856 CreateAppInfo("None", "None", "com.example.app", OrientationLock::NONE);
3857 appinfo_landscape_ =
3858 CreateAppInfo("Landscape", "Landscape", "com.example.app",
3859 OrientationLock::LANDSCAPE);
3860 appinfo_portrait_ = CreateAppInfo("Portrait", "Portrait", "com.example.app",
3861 OrientationLock::PORTRAIT);
3862 appinfo_current_ = CreateAppInfo(
3863 "LockCurrent", "current", "com.example.app", OrientationLock::CURRENT);
3864
3865 AddArcAppAndShortcut(appinfo_none_);
3866 AddArcAppAndShortcut(appinfo_landscape_);
3867 AddArcAppAndShortcut(appinfo_portrait_);
3868 AddArcAppAndShortcut(appinfo_current_);
3869
3870 ash::ScreenOrientationController* controller =
3871 ash::Shell::Get()->screen_orientation_controller();
3872
3873 // Creating a window with NONE orientation will not lock the screen.
3874 window_none_ = CreateArcWindow(window_app_id_none_);
3875 NotifyOnTaskCreated(appinfo_none_, task_id_none_);
3876 EXPECT_FALSE(controller->rotation_locked());
3877 EXPECT_EQ(display::Display::ROTATE_0,
3878 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
3879
3880 // Create a arc window with PORTRAIT orientation locks the screen to 90.
3881 window_portrait_ = CreateArcWindow(window_app_id_portrait_);
3882 NotifyOnTaskCreated(appinfo_portrait_, task_id_portrait_);
3883 EXPECT_TRUE(controller->rotation_locked());
3884 EXPECT_EQ(display::Display::ROTATE_90,
3885 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
3886
3887 // Create a arc window with LANDSCAPE orientation locks the screen to 0.
3888 window_landscape_ = CreateArcWindow(window_app_id_landscape_);
3889 NotifyOnTaskCreated(appinfo_landscape_, task_id_landscape_);
3890 EXPECT_TRUE(controller->rotation_locked());
3891 EXPECT_EQ(display::Display::ROTATE_0,
3892 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
3893 }
3894
3895 int32_t task_id_none_ = 1;
3896 int32_t task_id_landscape_ = 2;
3897 int32_t task_id_portrait_ = 3;
3898 int32_t task_id_current_ = 4;
3899
3900 // This needs to be kept on the instance because window's property has
3901 // refeference to this.
3902 std::string window_app_id_none_ = {"org.chromium.arc.1"};
3903 std::string window_app_id_landscape_ = {"org.chromium.arc.2"};
3904 std::string window_app_id_portrait_ = {"org.chromium.arc.3"};
3905 std::string window_app_id_current_ = {"org.chromium.arc.4"};
3906
3907 arc::mojom::AppInfo appinfo_none_;
3908 arc::mojom::AppInfo appinfo_landscape_;
3909 arc::mojom::AppInfo appinfo_portrait_;
3910 arc::mojom::AppInfo appinfo_current_;
3911
3912 views::Widget* window_none_ = nullptr;
3913 views::Widget* window_landscape_ = nullptr;
3914 views::Widget* window_portrait_ = nullptr;
3915 views::Widget* window_current_ = nullptr;
3916
3917 private:
3918 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerOrientationTest);
3919 };
3920
3921 INSTANTIATE_TEST_CASE_P(,
3922 ChromeLauncherControllerOrientationTest,
3923 ::testing::Bool());
3924
3925 class ChromeLauncherControllerArcDefaultAppsTest
3926 : public ChromeLauncherControllerImplTest,
3927 public ::testing::WithParamInterface<bool> {
3928 public:
3929 ChromeLauncherControllerArcDefaultAppsTest() {}
3930 ~ChromeLauncherControllerArcDefaultAppsTest() override {}
3931
3932 protected:
3933 void SetUp() override {
3934 if (GetParam())
3935 arc::SetArcAlwaysStartForTesting();
3936 ArcDefaultAppList::UseTestAppsDirectory();
3937 ChromeLauncherControllerImplTest::SetUp();
3938 }
3939
3940 private:
3941 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerArcDefaultAppsTest);
3942 };
3943
3944 INSTANTIATE_TEST_CASE_P(,
3945 ChromeLauncherControllerArcDefaultAppsTest,
3946 ::testing::Bool());
3947
3948 } // namespace
3949
3950 TEST_P(ChromeLauncherControllerOrientationTest,
3951 ArcOrientationLockBeforeWindowReady) {
3952 ASSERT_TRUE(display::Display::HasInternalDisplay());
3953
3954 extension_service_->AddExtension(arc_support_host_.get());
3955 EnablePlayStore(true);
3956
3957 InitLauncherController();
3958
3959 ash::ScreenOrientationController* controller =
3960 ash::Shell::Get()->screen_orientation_controller();
3961
3962 std::string app_id1("org.chromium.arc.1");
3963 int task_id1 = 1;
3964 arc::mojom::AppInfo appinfo1 =
3965 CreateAppInfo("Test1", "test", "com.example.app", OrientationLock::NONE);
3966
3967 AddArcAppAndShortcut(appinfo1);
3968 NotifyOnTaskCreated(appinfo1, task_id1);
3969 NotifyOnTaskOrientationLockRequested(task_id1, OrientationLock::PORTRAIT);
3970
3971 // Widgets will be deleted by the system.
3972 CreateArcWindow(app_id1);
3973
3974 EXPECT_FALSE(controller->rotation_locked());
3975
3976 EnableTabletMode(true);
3977 EXPECT_TRUE(controller->rotation_locked());
3978 EXPECT_EQ(display::Display::ROTATE_90,
3979 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
3980
3981 std::string app_id2("org.chromium.arc.2");
3982 int task_id2 = 2;
3983 arc::mojom::AppInfo appinfo2 =
3984 CreateAppInfo("Test2", "test", "com.example.app", OrientationLock::NONE);
3985 // Create in tablet mode.
3986 AddArcAppAndShortcut(appinfo2);
3987 NotifyOnTaskCreated(appinfo2, task_id2);
3988 NotifyOnTaskOrientationLockRequested(task_id2, OrientationLock::LANDSCAPE);
3989 EXPECT_TRUE(controller->rotation_locked());
3990 EXPECT_EQ(display::Display::ROTATE_90,
3991 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
3992
3993 // The screen will be locked when the window is created.
3994 CreateArcWindow(app_id2);
3995 EXPECT_TRUE(controller->rotation_locked());
3996 EXPECT_EQ(display::Display::ROTATE_0,
3997 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
3998 }
3999
4000 TEST_P(ChromeLauncherControllerOrientationTest, ArcOrientationLock) {
4001 ASSERT_TRUE(display::Display::HasInternalDisplay());
4002
4003 extension_service_->AddExtension(arc_support_host_.get());
4004 EnablePlayStore(true);
4005 EnableTabletMode(true);
4006
4007 InitLauncherController();
4008
4009 InitApps();
4010 ash::ScreenOrientationController* controller =
4011 ash::Shell::Get()->screen_orientation_controller();
4012
4013 // Activating a window with NON orientation unlocks the screen.
4014 window_none_->Activate();
4015 EXPECT_FALSE(controller->rotation_locked());
4016 EXPECT_EQ(display::Display::ROTATE_0,
4017 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4018
4019 // Activating a window with PORTRAIT orientation locks the screen to 90.
4020 window_portrait_->Activate();
4021 EXPECT_TRUE(controller->rotation_locked());
4022 EXPECT_EQ(display::Display::ROTATE_90,
4023 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4024
4025 // Disable Tablet mode, and make sure the screen is unlocked.
4026 EnableTabletMode(false);
4027 EXPECT_FALSE(controller->rotation_locked());
4028 EXPECT_EQ(display::Display::ROTATE_0,
4029 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4030
4031 // Re-enable Tablet mode, and make sure the screen is locked to 90.
4032 EnableTabletMode(true);
4033 EXPECT_TRUE(controller->rotation_locked());
4034 EXPECT_EQ(display::Display::ROTATE_90,
4035 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4036
4037 window_portrait_->Activate();
4038 EXPECT_TRUE(controller->rotation_locked());
4039 EXPECT_EQ(display::Display::ROTATE_90,
4040 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4041
4042 window_landscape_->Activate();
4043 EXPECT_TRUE(controller->rotation_locked());
4044 EXPECT_EQ(display::Display::ROTATE_0,
4045 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4046
4047 // OnTaskOrientationLockRequested can overwrite the current lock.
4048 NotifyOnTaskOrientationLockRequested(task_id_landscape_,
4049 OrientationLock::NONE);
4050 EXPECT_FALSE(controller->rotation_locked());
4051 EXPECT_EQ(display::Display::ROTATE_0,
4052 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4053
4054 NotifyOnTaskOrientationLockRequested(task_id_landscape_,
4055 OrientationLock::PORTRAIT);
4056 EXPECT_TRUE(controller->rotation_locked());
4057 EXPECT_EQ(display::Display::ROTATE_90,
4058 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4059
4060 // Non active window won't change the lock.
4061 NotifyOnTaskOrientationLockRequested(task_id_none_,
4062 OrientationLock::LANDSCAPE);
4063 EXPECT_TRUE(controller->rotation_locked());
4064 EXPECT_EQ(display::Display::ROTATE_90,
4065 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4066
4067 // But activating it will change the locked orinetation.
4068 window_none_->Activate();
4069 EXPECT_TRUE(controller->rotation_locked());
4070 EXPECT_EQ(display::Display::ROTATE_0,
4071 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4072
4073 // OnTaskOrientationLockRequested will not lock the screen in non Tablet mode.
4074 EnableTabletMode(false);
4075 EXPECT_FALSE(controller->rotation_locked());
4076 EXPECT_EQ(display::Display::ROTATE_0,
4077 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4078
4079 NotifyOnTaskOrientationLockRequested(task_id_none_,
4080 OrientationLock::PORTRAIT);
4081 EXPECT_FALSE(controller->rotation_locked());
4082 EXPECT_EQ(display::Display::ROTATE_0,
4083 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4084
4085 // But it remembers the orientation lock and use it when Tablet mode is
4086 // enabled.
4087 EnableTabletMode(true);
4088 EXPECT_TRUE(controller->rotation_locked());
4089 EXPECT_EQ(display::Display::ROTATE_90,
4090 display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
4091
4092 // Manually unlock first.
4093 NotifyOnTaskOrientationLockRequested(task_id_none_, OrientationLock::NONE);
4094 EXPECT_FALSE(controller->rotation_locked());
4095 }
4096
4097 TEST_P(ChromeLauncherControllerArcDefaultAppsTest, DefaultApps) {
4098 arc_test_.SetUp(profile());
4099 InitLauncherController();
4100 // TODO(crbug.com/709297): Fix this workaround to prevent a TearDown crash.
4101 std::vector<std::unique_ptr<AppIconLoader>> no_loaders;
4102 launcher_controller_->SetAppIconLoadersForTest(no_loaders);
4103
4104 ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
4105 EnablePlayStore(false);
4106 EXPECT_FALSE(arc::IsArcPlayStoreEnabledForProfile(profile()));
4107 ASSERT_TRUE(prefs->GetAppIds().size());
4108
4109 const std::string app_id =
4110 ArcAppTest::GetAppId(arc_test_.fake_default_apps()[0]);
4111 EXPECT_EQ(ash::kInvalidShelfID,
4112 launcher_controller_->GetShelfIDForAppID(app_id));
4113 EXPECT_TRUE(arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON));
4114 EXPECT_TRUE(arc::IsArcPlayStoreEnabledForProfile(profile()));
4115 EXPECT_NE(ash::kInvalidShelfID,
4116 launcher_controller_->GetShelfIDForAppID(app_id));
4117
4118 // Stop ARC again. Shelf item should go away.
4119 EnablePlayStore(false);
4120 EXPECT_EQ(ash::kInvalidShelfID,
4121 launcher_controller_->GetShelfIDForAppID(app_id));
4122
4123 EXPECT_TRUE(arc::LaunchApp(profile(), app_id, ui::EF_LEFT_MOUSE_BUTTON));
4124 EXPECT_TRUE(arc::IsArcPlayStoreEnabledForProfile(profile()));
4125
4126 EXPECT_NE(ash::kInvalidShelfID,
4127 launcher_controller_->GetShelfIDForAppID(app_id));
4128 EXPECT_TRUE(launcher_controller_->GetArcDeferredLauncher()->HasApp(app_id));
4129
4130 std::string window_app_id("org.chromium.arc.1");
4131 CreateArcWindow(window_app_id);
4132 arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_default_apps()[0],
4133 std::string());
4134
4135 EXPECT_NE(ash::kInvalidShelfID,
4136 launcher_controller_->GetShelfIDForAppID(app_id));
4137 EXPECT_FALSE(launcher_controller_->GetArcDeferredLauncher()->HasApp(app_id));
4138 }
4139
4140 TEST_P(ChromeLauncherControllerArcDefaultAppsTest, PlayStoreDeferredLaunch) {
4141 // Add ARC host app to enable Play Store default app.
4142 extension_service_->AddExtension(arc_support_host_.get());
4143 arc_test_.SetUp(profile());
4144 ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
4145 EXPECT_TRUE(prefs->IsRegistered(arc::kPlayStoreAppId));
4146
4147 InitLauncherController();
4148
4149 EnablePlayStore(true);
4150
4151 // Pin Play Store. It should be pinned but not scheduled for deferred launch.
4152 launcher_controller_->PinAppWithID(arc::kPlayStoreAppId);
4153 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
4154 EXPECT_FALSE(launcher_controller_->GetArcDeferredLauncher()->HasApp(
4155 arc::kPlayStoreAppId));
4156
4157 // Simulate click. This should schedule Play Store for deferred launch.
4158 ash::ShelfItemDelegate* item_delegate = model_->GetShelfItemDelegate(
4159 launcher_controller_->GetShelfIDForAppID(arc::kPlayStoreAppId));
4160 EXPECT_TRUE(item_delegate);
4161 SelectItem(item_delegate);
4162 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
4163 EXPECT_TRUE(launcher_controller_->GetArcDeferredLauncher()->HasApp(
4164 arc::kPlayStoreAppId));
4165 }
4166
4167 // Checks the case when several app items have the same ordinal position (which
4168 // is valid case).
4169 TEST_F(ChromeLauncherControllerImplTest, CheckPositionConflict) {
4170 InitLauncherController();
4171
4172 extension_service_->AddExtension(extension1_.get());
4173 extension_service_->AddExtension(extension2_.get());
4174 extension_service_->AddExtension(extension3_.get());
4175
4176 syncer::SyncChangeList sync_list;
4177 InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
4178 InsertAddPinChange(&sync_list, 1, extension1_->id());
4179 InsertAddPinChange(&sync_list, 1, extension2_->id());
4180 InsertAddPinChange(&sync_list, 1, extension3_->id());
4181 SendPinChanges(sync_list, true);
4182
4183 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
4184
4185 const syncer::StringOrdinal position_chrome =
4186 app_service_->GetPinPosition(extension_misc::kChromeAppId);
4187 const syncer::StringOrdinal position_1 =
4188 app_service_->GetPinPosition(extension1_->id());
4189 const syncer::StringOrdinal position_2 =
4190 app_service_->GetPinPosition(extension2_->id());
4191 const syncer::StringOrdinal position_3 =
4192 app_service_->GetPinPosition(extension3_->id());
4193 EXPECT_TRUE(position_chrome.LessThan(position_1));
4194 EXPECT_TRUE(position_1.Equals(position_2));
4195 EXPECT_TRUE(position_2.Equals(position_3));
4196
4197 // Move Chrome between App1 and App2.
4198 // Note, move target_index is in context when moved element is removed from
4199 // array first.
4200 model_->Move(1, 2);
4201 EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus());
4202
4203 // Expect sync positions for only Chrome is updated and its resolution is
4204 // after all duplicated ordinals.
4205 EXPECT_TRUE(position_3.LessThan(
4206 app_service_->GetPinPosition(extension_misc::kChromeAppId)));
4207 EXPECT_TRUE(
4208 position_1.Equals(app_service_->GetPinPosition(extension1_->id())));
4209 EXPECT_TRUE(
4210 position_1.Equals(app_service_->GetPinPosition(extension1_->id())));
4211 EXPECT_TRUE(
4212 position_2.Equals(app_service_->GetPinPosition(extension2_->id())));
4213 EXPECT_TRUE(
4214 position_3.Equals(app_service_->GetPinPosition(extension3_->id())));
4215 }
4216
4217 // Test the case when sync app is turned off and we need to use local copy to
4218 // support user's pins.
4219 TEST_F(ChromeLauncherControllerImplTest, SyncOffLocalUpdate) {
4220 InitLauncherController();
4221
4222 extension_service_->AddExtension(extension1_.get());
4223 extension_service_->AddExtension(extension2_.get());
4224
4225 syncer::SyncChangeList sync_list;
4226 InsertAddPinChange(&sync_list, 0, extension_misc::kChromeAppId);
4227 InsertAddPinChange(&sync_list, 1, extension1_->id());
4228 InsertAddPinChange(&sync_list, 1, extension2_->id());
4229 SendPinChanges(sync_list, true);
4230
4231 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
4232
4233 syncer::SyncDataList copy_sync_list =
4234 app_service_->GetAllSyncData(syncer::APP_LIST);
4235
4236 app_service_->StopSyncing(syncer::APP_LIST);
4237 RecreateLauncherController()->Init();
4238
4239 // Pinned state should not change.
4240 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
4241 launcher_controller_->UnpinAppWithID(extension2_->id());
4242 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
4243
4244 // Resume syncing and sync information overrides local copy.
4245 StartAppSyncService(copy_sync_list);
4246 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
4247 }
4248
4249 // Tests that shelf profile preferences are loaded on login.
4250 TEST_F(ChromeLauncherControllerImplTest, PrefsLoadedOnLogin) {
4251 PrefService* prefs = profile()->GetTestingPrefService();
4252 prefs->SetString(prefs::kShelfAlignmentLocal, "Left");
4253 prefs->SetString(prefs::kShelfAlignment, "Left");
4254 prefs->SetString(prefs::kShelfAutoHideBehaviorLocal, "Always");
4255 prefs->SetString(prefs::kShelfAutoHideBehavior, "Always");
4256
4257 TestChromeLauncherControllerImpl* test_launcher_controller =
4258 shell_delegate_->CreateTestLauncherController(profile());
4259
4260 // Simulate login for the test controller.
4261 test_launcher_controller->ReleaseProfile();
4262 test_launcher_controller->AttachProfile(profile());
4263 base::RunLoop().RunUntilIdle();
4264
4265 TestShelfController* shelf_controller =
4266 test_launcher_controller->test_shelf_controller();
4267 ASSERT_TRUE(shelf_controller);
4268 EXPECT_EQ(ash::SHELF_ALIGNMENT_LEFT, shelf_controller->alignment());
4269 EXPECT_EQ(1u, shelf_controller->alignment_change_count());
4270 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
4271 shelf_controller->auto_hide());
4272 EXPECT_EQ(1u, shelf_controller->auto_hide_change_count());
4273 }
4274
4275 // Tests that the shelf controller's changes are not wastefully echoed back.
4276 TEST_F(ChromeLauncherControllerImplTest, DoNotEchoShelfControllerChanges) {
4277 TestChromeLauncherControllerImpl* test_launcher_controller =
4278 shell_delegate_->CreateTestLauncherController(profile());
4279
4280 // Simulate login for the test controller.
4281 test_launcher_controller->ReleaseProfile();
4282 test_launcher_controller->AttachProfile(profile());
4283 base::RunLoop().RunUntilIdle();
4284
4285 TestShelfController* shelf_controller =
4286 test_launcher_controller->test_shelf_controller();
4287 ASSERT_TRUE(shelf_controller);
4288 EXPECT_EQ(ash::SHELF_ALIGNMENT_BOTTOM, shelf_controller->alignment());
4289 EXPECT_EQ(1u, shelf_controller->alignment_change_count());
4290 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf_controller->auto_hide());
4291 EXPECT_EQ(1u, shelf_controller->auto_hide_change_count());
4292
4293 // Changing settings via the shelf controller causes the launcher controller
4294 // to update profile prefs. The launcher controller's prefs observation should
4295 // not cause those same changes to be echoed back to the shelf controller.
4296 int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
4297 shelf_controller->SetAlignment(ash::SHELF_ALIGNMENT_LEFT, display_id);
4298 EXPECT_EQ(2u, shelf_controller->alignment_change_count());
4299 shelf_controller->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
4300 display_id);
4301 EXPECT_EQ(2u, shelf_controller->auto_hide_change_count());
4302 base::RunLoop().RunUntilIdle();
4303
4304 EXPECT_EQ(ash::SHELF_ALIGNMENT_LEFT, shelf_controller->alignment());
4305 EXPECT_EQ(2u, shelf_controller->alignment_change_count());
4306 EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
4307 shelf_controller->auto_hide());
4308 EXPECT_EQ(2u, shelf_controller->auto_hide_change_count());
4309
4310 PrefService* prefs = profile()->GetTestingPrefService();
4311 EXPECT_EQ("Left", prefs->GetString(prefs::kShelfAlignmentLocal));
4312 EXPECT_EQ("Left", prefs->GetString(prefs::kShelfAlignment));
4313 EXPECT_EQ("Always", prefs->GetString(prefs::kShelfAutoHideBehaviorLocal));
4314 EXPECT_EQ("Always", prefs->GetString(prefs::kShelfAutoHideBehavior));
4315 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698