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.
5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
11 #include "ash/ash_switches.h"
12 #include "ash/shelf/shelf_item_delegate_manager.h"
13 #include "ash/shelf/shelf_model.h"
14 #include "ash/shelf/shelf_model_observer.h"
15 #include "ash/shell.h"
16 #include "ash/test/shelf_item_delegate_manager_test_api.h"
17 #include "base/command_line.h"
18 #include "base/compiler_specific.h"
19 #include "base/files/file_path.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "chrome/browser/extensions/extension_service.h"
25 #include "chrome/browser/extensions/test_extension_system.h"
26 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
27 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
28 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
29 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
30 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_commands.h"
32 #include "chrome/browser/ui/browser_finder.h"
33 #include "chrome/browser/ui/browser_list.h"
34 #include "chrome/browser/ui/browser_tabstrip.h"
35 #include "chrome/browser/ui/host_desktop.h"
36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
37 #include "chrome/common/extensions/extension_constants.h"
38 #include "chrome/common/pref_names.h"
39 #include "chrome/test/base/browser_with_test_window_test.h"
40 #include "chrome/test/base/testing_pref_service_syncable.h"
41 #include "chrome/test/base/testing_profile.h"
42 #include "content/public/browser/web_contents.h"
43 #include "extensions/common/extension.h"
44 #include "extensions/common/manifest_constants.h"
45 #include "testing/gtest/include/gtest/gtest.h"
46 #include "ui/aura/client/window_tree_client.h"
47 #include "ui/base/models/menu_model.h"
49 #if defined(OS_CHROMEOS)
50 #include "ash/test/test_session_state_delegate.h"
51 #include "ash/test/test_shell_delegate.h"
52 #include "chrome/browser/apps/scoped_keep_alive.h"
53 #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
54 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
55 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
56 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
57 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
58 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
59 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
60 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
61 #include "chrome/common/chrome_constants.h"
62 #include "chrome/common/chrome_switches.h"
63 #include "chrome/test/base/testing_browser_process.h"
64 #include "chrome/test/base/testing_profile_manager.h"
65 #include "content/public/browser/web_contents_observer.h"
66 #include "content/public/test/test_utils.h"
67 #include "extensions/browser/app_window/app_window_contents.h"
68 #include "extensions/browser/app_window/app_window_registry.h"
69 #include "extensions/browser/app_window/native_app_window.h"
70 #include "ui/aura/window.h"
73 using base::ASCIIToUTF16;
74 using extensions::Extension;
75 using extensions::Manifest;
76 using extensions::UnloadedExtensionInfo;
79 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
80 const char* gmail_url = "https://mail.google.com/mail/u";
81 const char* kGmailLaunchURL = "https://mail.google.com/mail/ca";
83 #if defined(OS_CHROMEOS)
84 // An extension prefix.
85 const char kCrxAppPrefix[] = "_crx_";
88 // ShelfModelObserver implementation that tracks what messages are invoked.
89 class TestShelfModelObserver : public ash::ShelfModelObserver {
91 TestShelfModelObserver()
97 virtual ~TestShelfModelObserver() {
100 // Overridden from ash::ShelfModelObserver:
101 virtual void ShelfItemAdded(int index) OVERRIDE {
106 virtual void ShelfItemRemoved(int index, ash::ShelfID id) OVERRIDE {
111 virtual void ShelfItemChanged(int index,
112 const ash::ShelfItem& old_item) OVERRIDE {
117 virtual void ShelfItemMoved(int start_index, int target_index) OVERRIDE {
118 last_index_ = target_index;
121 virtual void ShelfStatusChanged() OVERRIDE {
124 void clear_counts() {
131 int added() const { return added_; }
132 int removed() const { return removed_; }
133 int changed() const { return changed_; }
134 int last_index() const { return last_index_; }
142 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver);
145 // Test implementation of AppIconLoader.
146 class TestAppIconLoaderImpl : public extensions::AppIconLoader {
148 TestAppIconLoaderImpl() : fetch_count_(0) {
151 virtual ~TestAppIconLoaderImpl() {
154 // AppIconLoader implementation:
155 virtual void FetchImage(const std::string& id) OVERRIDE {
159 virtual void ClearImage(const std::string& id) OVERRIDE {
162 virtual void UpdateImage(const std::string& id) OVERRIDE {
165 int fetch_count() const { return fetch_count_; }
170 DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl);
173 // Test implementation of AppTabHelper.
174 class TestAppTabHelperImpl : public ChromeLauncherController::AppTabHelper {
176 TestAppTabHelperImpl() {}
177 virtual ~TestAppTabHelperImpl() {}
179 // Sets the id for the specified tab. The id is removed if Remove() is
181 void SetAppID(content::WebContents* tab, const std::string& id) {
182 tab_id_map_[tab] = id;
185 // Returns true if there is an id registered for |tab|.
186 bool HasAppID(content::WebContents* tab) const {
187 return tab_id_map_.find(tab) != tab_id_map_.end();
190 // AppTabHelper implementation:
191 virtual std::string GetAppID(content::WebContents* tab) OVERRIDE {
192 return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] :
196 virtual bool IsValidIDForCurrentUser(const std::string& id) OVERRIDE {
197 for (TabToStringMap::const_iterator i = tab_id_map_.begin();
198 i != tab_id_map_.end(); ++i) {
205 virtual void SetCurrentUser(Profile* profile) OVERRIDE {
206 // We can ignore this for now.
210 typedef std::map<content::WebContents*, std::string> TabToStringMap;
212 TabToStringMap tab_id_map_;
214 DISALLOW_COPY_AND_ASSIGN(TestAppTabHelperImpl);
217 // Test implementation of a V2 app launcher item controller.
218 class TestV2AppLauncherItemController : public LauncherItemController {
220 TestV2AppLauncherItemController(const std::string& app_id,
221 ChromeLauncherController* controller)
222 : LauncherItemController(LauncherItemController::TYPE_APP,
227 virtual ~TestV2AppLauncherItemController() {}
229 // Override for LauncherItemController:
230 virtual bool IsOpen() const OVERRIDE { return true; }
231 virtual bool IsVisible() const OVERRIDE { return true; }
232 virtual void Launch(ash::LaunchSource source, int event_flags) OVERRIDE {}
233 virtual bool Activate(ash::LaunchSource source) OVERRIDE { return false; }
234 virtual void Close() OVERRIDE {}
235 virtual bool ItemSelected(const ui::Event& event) OVERRIDE { return false; }
236 virtual base::string16 GetTitle() OVERRIDE { return base::string16(); }
237 virtual ChromeLauncherAppMenuItems GetApplicationList(
238 int event_flags) OVERRIDE {
239 ChromeLauncherAppMenuItems items;
241 new ChromeLauncherAppMenuItem(base::string16(), NULL, false));
243 new ChromeLauncherAppMenuItem(base::string16(), NULL, false));
246 virtual ui::MenuModel* CreateContextMenu(aura::Window* root_window) OVERRIDE {
249 virtual ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) OVERRIDE {
252 virtual bool IsDraggable() OVERRIDE { return false; }
253 virtual bool ShouldShowTooltip() OVERRIDE { return false; }
256 DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController);
261 class ChromeLauncherControllerTest : public BrowserWithTestWindowTest {
263 ChromeLauncherControllerTest()
264 : BrowserWithTestWindowTest(
265 Browser::TYPE_TABBED,
266 chrome::HOST_DESKTOP_TYPE_ASH,
268 test_controller_(NULL),
269 extension_service_(NULL) {
272 virtual ~ChromeLauncherControllerTest() {
275 virtual void SetUp() OVERRIDE {
276 BrowserWithTestWindowTest::SetUp();
278 model_.reset(new ash::ShelfModel);
279 model_observer_.reset(new TestShelfModelObserver);
280 model_->AddObserver(model_observer_.get());
282 if (ash::Shell::HasInstance()) {
283 item_delegate_manager_ =
284 ash::Shell::GetInstance()->shelf_item_delegate_manager();
286 item_delegate_manager_ =
287 new ash::ShelfItemDelegateManager(model_.get());
290 base::DictionaryValue manifest;
291 manifest.SetString(extensions::manifest_keys::kName,
292 "launcher controller test extension");
293 manifest.SetString(extensions::manifest_keys::kVersion, "1");
294 manifest.SetString(extensions::manifest_keys::kDescription,
295 "for testing pinned apps");
297 extensions::TestExtensionSystem* extension_system(
298 static_cast<extensions::TestExtensionSystem*>(
299 extensions::ExtensionSystem::Get(profile())));
300 extension_service_ = extension_system->CreateExtensionService(
301 CommandLine::ForCurrentProcess(), base::FilePath(), false);
304 extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
307 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
309 extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
312 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
314 // Fake gmail extension.
315 base::DictionaryValue manifest_gmail;
316 manifest_gmail.SetString(extensions::manifest_keys::kName,
317 "Gmail launcher controller test extension");
318 manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1");
319 manifest_gmail.SetString(extensions::manifest_keys::kDescription,
320 "for testing pinned Gmail");
321 manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL,
323 base::ListValue* list = new base::ListValue();
324 list->Append(new base::StringValue("*://mail.google.com/mail/ca"));
325 manifest_gmail.Set(extensions::manifest_keys::kWebURLs, list);
327 extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
330 extension_misc::kGmailAppId,
333 // Fake search extension.
334 extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
337 extension_misc::kGoogleSearchAppId,
339 extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
342 "cccccccccccccccccccccccccccccccc",
344 extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
347 "dddddddddddddddddddddddddddddddd",
349 extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
352 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
354 extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
357 "ffffffffffffffffffffffffffffffff",
361 // Creates a running V2 app (not pinned) of type |app_id|.
362 virtual void CreateRunningV2App(const std::string& app_id) {
363 DCHECK(!test_controller_);
365 launcher_controller_->CreateAppShortcutLauncherItemWithType(
367 model_->item_count(),
368 ash::TYPE_PLATFORM_APP);
370 // Change the created launcher controller into a V2 app controller.
371 test_controller_ = new TestV2AppLauncherItemController(app_id,
372 launcher_controller_.get());
373 launcher_controller_->SetItemController(id, test_controller_);
376 // Sets the stage for a multi user test.
377 virtual void SetUpMultiUserScenario(base::ListValue* user_a,
378 base::ListValue* user_b) {
379 InitLauncherController();
380 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
382 // Set an empty pinned pref to begin with.
383 base::ListValue no_user;
384 SetShelfChromeIconIndex(0);
385 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
387 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
389 // Assume all applications have been added already.
390 extension_service_->AddExtension(extension1_.get());
391 extension_service_->AddExtension(extension2_.get());
392 extension_service_->AddExtension(extension3_.get());
393 extension_service_->AddExtension(extension4_.get());
394 extension_service_->AddExtension(extension5_.get());
395 extension_service_->AddExtension(extension6_.get());
396 extension_service_->AddExtension(extension7_.get());
397 extension_service_->AddExtension(extension8_.get());
398 // There should be nothing in the list by now.
399 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
401 // Set user a preferences.
402 InsertPrefValue(user_a, 0, extension1_->id());
403 InsertPrefValue(user_a, 1, extension2_->id());
404 InsertPrefValue(user_a, 2, extension3_->id());
405 InsertPrefValue(user_a, 3, extension4_->id());
406 InsertPrefValue(user_a, 4, extension5_->id());
407 InsertPrefValue(user_a, 5, extension6_->id());
409 // Set user b preferences.
410 InsertPrefValue(user_b, 0, extension7_->id());
411 InsertPrefValue(user_b, 1, extension8_->id());
414 virtual void TearDown() OVERRIDE {
415 if (!ash::Shell::HasInstance())
416 delete item_delegate_manager_;
417 model_->RemoveObserver(model_observer_.get());
418 model_observer_.reset();
419 launcher_controller_.reset();
422 BrowserWithTestWindowTest::TearDown();
425 void AddAppListLauncherItem() {
426 ash::ShelfItem app_list;
427 app_list.type = ash::TYPE_APP_LIST;
428 model_->Add(app_list);
431 void InitLauncherController() {
432 AddAppListLauncherItem();
433 launcher_controller_.reset(
434 new ChromeLauncherController(profile(), model_.get()));
435 if (!ash::Shell::HasInstance())
436 SetShelfItemDelegateManager(item_delegate_manager_);
437 launcher_controller_->Init();
440 void InitLauncherControllerWithBrowser() {
441 chrome::NewTab(browser());
442 BrowserList::SetLastActive(browser());
443 InitLauncherController();
446 void SetAppIconLoader(extensions::AppIconLoader* loader) {
447 launcher_controller_->SetAppIconLoaderForTest(loader);
450 void SetAppTabHelper(ChromeLauncherController::AppTabHelper* helper) {
451 launcher_controller_->SetAppTabHelperForTest(helper);
454 void SetShelfItemDelegateManager(ash::ShelfItemDelegateManager* manager) {
455 launcher_controller_->SetShelfItemDelegateManagerForTest(manager);
458 void InsertPrefValue(base::ListValue* pref_value,
460 const std::string& extension_id) {
461 base::DictionaryValue* entry = new base::DictionaryValue();
462 entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id);
463 pref_value->Insert(index, entry);
466 // Gets the currently configured app launchers from the controller.
467 void GetAppLaunchers(ChromeLauncherController* controller,
468 std::vector<std::string>* launchers) {
470 for (ash::ShelfItems::const_iterator iter(model_->items().begin());
471 iter != model_->items().end(); ++iter) {
472 ChromeLauncherController::IDToItemControllerMap::const_iterator
473 entry(controller->id_to_item_controller_map_.find(iter->id));
474 if (iter->type == ash::TYPE_APP_SHORTCUT &&
475 entry != controller->id_to_item_controller_map_.end()) {
476 launchers->push_back(entry->second->app_id());
481 // Get the setup of the currently shown launcher items in one string.
482 // Each pinned element will start with a big letter, each running but not
483 // pinned V1 app will start with a small letter and each running but not
484 // pinned V2 app will start with a '*' + small letter.
485 std::string GetPinnedAppStatus() {
487 for (int i = 0; i < model_->item_count(); i++) {
490 switch (model_->items()[i].type) {
491 case ash::TYPE_PLATFORM_APP:
494 case ash::TYPE_WINDOWED_APP: {
495 const std::string& app =
496 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id);
497 if (app == extension1_->id()) {
500 launcher_controller_->IsAppPinned(extension1_->id()));
501 } else if (app == extension2_->id()) {
504 launcher_controller_->IsAppPinned(extension2_->id()));
505 } else if (app == extension3_->id()) {
508 launcher_controller_->IsAppPinned(extension3_->id()));
509 } else if (app == extension4_->id()) {
512 launcher_controller_->IsAppPinned(extension4_->id()));
513 } else if (app == extension5_->id()) {
516 launcher_controller_->IsAppPinned(extension5_->id()));
517 } else if (app == extension6_->id()) {
520 launcher_controller_->IsAppPinned(extension6_->id()));
521 } else if (app == extension7_->id()) {
524 launcher_controller_->IsAppPinned(extension7_->id()));
525 } else if (app == extension8_->id()) {
528 launcher_controller_->IsAppPinned(extension8_->id()));
534 case ash::TYPE_APP_SHORTCUT: {
535 const std::string& app =
536 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id);
537 if (app == extension1_->id()) {
539 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
540 } else if (app == extension2_->id()) {
542 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
543 } else if (app == extension3_->id()) {
545 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
546 } else if (app == extension4_->id()) {
548 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
549 } else if (app == extension5_->id()) {
551 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension5_->id()));
552 } else if (app == extension6_->id()) {
554 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension6_->id()));
555 } else if (app == extension7_->id()) {
557 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension7_->id()));
558 } else if (app == extension8_->id()) {
560 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension8_->id()));
566 case ash::TYPE_BROWSER_SHORTCUT:
569 case ash::TYPE_APP_LIST:
580 // Set the index at which the chrome icon should be.
581 void SetShelfChromeIconIndex(int index) {
582 profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
586 // Remember the order of unpinned but running applications for the current
588 void RememberUnpinnedRunningApplicationOrder() {
589 launcher_controller_->RememberUnpinnedRunningApplicationOrder();
592 // Restore the order of running but unpinned applications for a given user.
593 void RestoreUnpinnedRunningApplicationOrder(const std::string& user_id) {
594 launcher_controller_->RestoreUnpinnedRunningApplicationOrder(user_id);
597 // Needed for extension service & friends to work.
598 scoped_refptr<Extension> extension1_;
599 scoped_refptr<Extension> extension2_;
600 scoped_refptr<Extension> extension3_;
601 scoped_refptr<Extension> extension4_;
602 scoped_refptr<Extension> extension5_;
603 scoped_refptr<Extension> extension6_;
604 scoped_refptr<Extension> extension7_;
605 scoped_refptr<Extension> extension8_;
606 scoped_ptr<ChromeLauncherController> launcher_controller_;
607 scoped_ptr<TestShelfModelObserver> model_observer_;
608 scoped_ptr<ash::ShelfModel> model_;
610 // |item_delegate_manager_| owns |test_controller_|.
611 LauncherItemController* test_controller_;
613 ExtensionService* extension_service_;
615 ash::ShelfItemDelegateManager* item_delegate_manager_;
618 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerTest);
621 #if defined(OS_CHROMEOS)
622 // A browser window proxy which is able to associate an aura native window with
624 class TestBrowserWindowAura : public TestBrowserWindow {
626 // |native_window| will still be owned by the caller after the constructor
628 explicit TestBrowserWindowAura(aura::Window* native_window)
629 : native_window_(native_window) {
631 virtual ~TestBrowserWindowAura() {}
633 virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
634 return native_window_.get();
637 Browser* browser() { return browser_.get(); }
639 void CreateBrowser(const Browser::CreateParams& params) {
640 Browser::CreateParams create_params = params;
641 create_params.window = this;
642 browser_.reset(new Browser(create_params));
646 scoped_ptr<Browser> browser_;
647 scoped_ptr<aura::Window> native_window_;
649 DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura);
652 // Creates a test browser window which has a native window.
653 scoped_ptr<TestBrowserWindowAura> CreateTestBrowserWindow(
654 const Browser::CreateParams& params) {
656 aura::Window* window = new aura::Window(NULL);
658 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
659 window->Init(aura::WINDOW_LAYER_TEXTURED);
662 scoped_ptr<TestBrowserWindowAura> browser_window(
663 new TestBrowserWindowAura(window));
664 browser_window->CreateBrowser(params);
665 return browser_window.Pass();
668 // Watches WebContents and blocks until it is destroyed. This is needed for
669 // the destruction of a V2 application.
670 class WebContentsDestroyedWatcher : public content::WebContentsObserver {
672 explicit WebContentsDestroyedWatcher(content::WebContents* web_contents)
673 : content::WebContentsObserver(web_contents),
674 message_loop_runner_(new content::MessageLoopRunner) {
675 EXPECT_TRUE(web_contents != NULL);
677 virtual ~WebContentsDestroyedWatcher() {}
679 // Waits until the WebContents is destroyed.
681 message_loop_runner_->Run();
685 // Overridden WebContentsObserver methods.
686 virtual void WebContentsDestroyed() OVERRIDE {
687 message_loop_runner_->Quit();
690 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
692 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedWatcher);
695 // A V1 windowed application.
696 class V1App : public TestBrowserWindow {
698 V1App(Profile* profile, const std::string& app_name) {
700 native_window_.reset(new aura::Window(NULL));
701 native_window_->set_id(0);
702 native_window_->SetType(ui::wm::WINDOW_TYPE_POPUP);
703 native_window_->Init(aura::WINDOW_LAYER_TEXTURED);
704 native_window_->Show();
705 aura::client::ParentWindowWithContext(native_window_.get(),
706 ash::Shell::GetPrimaryRootWindow(),
707 gfx::Rect(10, 10, 20, 30));
708 Browser::CreateParams params =
709 Browser::CreateParams::CreateForApp(kCrxAppPrefix + app_name,
710 true /* trusted_source */,
713 chrome::HOST_DESKTOP_TYPE_ASH);
714 params.window = this;
715 browser_.reset(new Browser(params));
716 chrome::AddTabAt(browser_.get(), GURL(), 0, true);
720 // close all tabs. Note that we do not need to destroy the browser itself.
721 browser_->tab_strip_model()->CloseAllTabs();
724 Browser* browser() { return browser_.get(); }
726 // TestBrowserWindow override:
727 virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
728 return native_window_.get();
732 // The associated browser with this app.
733 scoped_ptr<Browser> browser_;
735 // The native window we use.
736 scoped_ptr<aura::Window> native_window_;
738 DISALLOW_COPY_AND_ASSIGN(V1App);
741 // A V2 application which gets created with an |extension| and for a |profile|.
742 // Upon destruction it will properly close the application.
745 V2App(Profile* profile, const extensions::Extension* extension) {
746 window_ = new extensions::AppWindow(
748 new ChromeAppDelegate(make_scoped_ptr(new ScopedKeepAlive)),
750 extensions::AppWindow::CreateParams params =
751 extensions::AppWindow::CreateParams();
752 window_->Init(GURL(std::string()),
753 new extensions::AppWindowContentsImpl(window_), params);
757 WebContentsDestroyedWatcher destroyed_watcher(window_->web_contents());
758 window_->GetBaseWindow()->Close();
759 destroyed_watcher.Wait();
762 extensions::AppWindow* window() { return window_; }
765 // The app window which represents the application. Note that the window
766 // deletes itself asynchronously after window_->GetBaseWindow()->Close() gets
768 extensions::AppWindow* window_;
770 DISALLOW_COPY_AND_ASSIGN(V2App);
773 // The testing framework to test multi profile scenarios.
774 class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest
775 : public ChromeLauncherControllerTest {
777 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() {
780 virtual ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() {
783 // Overwrite the Setup function to enable multi profile and needed objects.
784 virtual void SetUp() OVERRIDE {
785 profile_manager_.reset(
786 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
788 ASSERT_TRUE(profile_manager_->SetUp());
790 // AvatarMenu and multiple profiles works after user logged in.
791 profile_manager_->SetLoggedIn(true);
793 // Initialize the UserManager singleton to a fresh FakeUserManager instance.
794 user_manager_enabler_.reset(
795 new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
797 // Initialize the rest.
798 ChromeLauncherControllerTest::SetUp();
800 // Get some base objects.
801 session_delegate()->set_logged_in_users(2);
802 shell_delegate_ = static_cast<ash::test::TestShellDelegate*>(
803 ash::Shell::GetInstance()->delegate());
804 shell_delegate_->set_multi_profiles_enabled(true);
807 virtual void TearDown() {
808 ChromeLauncherControllerTest::TearDown();
809 user_manager_enabler_.reset();
810 for (ProfileToNameMap::iterator it = created_profiles_.begin();
811 it != created_profiles_.end(); ++it)
812 profile_manager_->DeleteTestingProfile(it->second);
814 // A Task is leaked if we don't destroy everything, then run the message
816 base::MessageLoop::current()->PostTask(FROM_HERE,
817 base::MessageLoop::QuitClosure());
818 base::MessageLoop::current()->Run();
821 // Creates a profile for a given |user_name|. Note that this class will keep
822 // the ownership of the created object.
823 TestingProfile* CreateMultiUserProfile(const std::string& user_name) {
824 std::string email_string = user_name + "@example.com";
825 static_cast<ash::test::TestSessionStateDelegate*>(
826 ash::Shell::GetInstance()->session_state_delegate())
827 ->AddUser(email_string);
828 // Add a user to the fake user manager.
829 session_delegate()->AddUser(email_string);
830 GetFakeUserManager()->AddUser(email_string);
832 GetFakeUserManager()->LoginUser(email_string);
834 TestingProfile* profile =
835 profile_manager()->CreateTestingProfile(email_string);
836 EXPECT_TRUE(profile);
838 // Remember the profile name so that we can destroy it upon destruction.
839 created_profiles_[profile] = email_string;
840 if (chrome::MultiUserWindowManager::GetInstance())
841 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
842 if (launcher_controller_)
843 launcher_controller_->AdditionalUserAddedToSession(profile);
847 // Switch to another user.
848 void SwitchActiveUser(const std::string& name) {
849 session_delegate()->SwitchActiveUser(name);
850 GetFakeUserManager()->SwitchActiveUser(name);
851 chrome::MultiUserWindowManagerChromeOS* manager =
852 static_cast<chrome::MultiUserWindowManagerChromeOS*>(
853 chrome::MultiUserWindowManager::GetInstance());
854 manager->SetAnimationSpeedForTest(
855 chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
856 manager->ActiveUserChanged(name);
857 launcher_controller_->browser_status_monitor_for_test()->
858 ActiveUserChanged(name);
859 launcher_controller_->app_window_controller_for_test()->
860 ActiveUserChanged(name);
863 // Creates a browser with a |profile| and load a tab with a |title| and |url|.
864 Browser* CreateBrowserAndTabWithProfile(Profile* profile,
865 const std::string& title,
866 const std::string& url) {
867 Browser::CreateParams params(profile, chrome::HOST_DESKTOP_TYPE_ASH);
868 Browser* browser = chrome::CreateBrowserWithTestWindowForParams(¶ms);
869 chrome::NewTab(browser);
871 BrowserList::SetLastActive(browser);
872 NavigateAndCommitActiveTabWithTitle(
873 browser, GURL(url), ASCIIToUTF16(title));
877 // Creates a running V1 application.
878 // Note that with the use of the app_tab_helper as done below, this is only
879 // usable with a single v1 application.
880 V1App* CreateRunningV1App(Profile* profile,
881 const std::string& app_name,
882 const std::string& url) {
883 V1App* v1_app = new V1App(profile, app_name);
884 // Create a new app tab helper and assign it to the launcher so that this
885 // app gets properly detected.
886 // TODO(skuhne): Create a more intelligent app tab helper which is able to
887 // detect all running apps properly.
888 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
889 app_tab_helper->SetAppID(
890 v1_app->browser()->tab_strip_model()->GetWebContentsAt(0),
892 SetAppTabHelper(app_tab_helper);
894 NavigateAndCommitActiveTabWithTitle(
895 v1_app->browser(), GURL(url), ASCIIToUTF16(""));
899 ash::test::TestSessionStateDelegate* session_delegate() {
900 return static_cast<ash::test::TestSessionStateDelegate*>(
901 ash::Shell::GetInstance()->session_state_delegate());
903 ash::test::TestShellDelegate* shell_delegate() { return shell_delegate_; }
905 // Override BrowserWithTestWindowTest:
906 virtual TestingProfile* CreateProfile() OVERRIDE {
907 return CreateMultiUserProfile("user1");
909 virtual void DestroyProfile(TestingProfile* profile) OVERRIDE {
910 // Delete the profile through our profile manager.
911 ProfileToNameMap::iterator it = created_profiles_.find(profile);
912 DCHECK(it != created_profiles_.end());
913 profile_manager_->DeleteTestingProfile(it->second);
914 created_profiles_.erase(it);
918 typedef std::map<Profile*, std::string> ProfileToNameMap;
919 TestingProfileManager* profile_manager() { return profile_manager_.get(); }
921 chromeos::FakeUserManager* GetFakeUserManager() {
922 return static_cast<chromeos::FakeUserManager*>(
923 user_manager::UserManager::Get());
926 scoped_ptr<TestingProfileManager> profile_manager_;
927 scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
929 ash::test::TestShellDelegate* shell_delegate_;
931 ProfileToNameMap created_profiles_;
933 DISALLOW_COPY_AND_ASSIGN(
934 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest);
936 #endif // defined(OS_CHROMEOS)
939 TEST_F(ChromeLauncherControllerTest, DefaultApps) {
940 InitLauncherController();
941 // Model should only contain the browser shortcut and app list items.
942 EXPECT_EQ(2, model_->item_count());
943 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
944 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
945 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
947 // Installing |extension3_| should add it to the launcher - behind the
949 extension_service_->AddExtension(extension3_.get());
950 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
951 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
952 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
955 // Check that the restauration of launcher items is happening in the same order
956 // as the user has pinned them (on another system) when they are synced reverse
958 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsReverseOrder) {
959 InitLauncherController();
961 base::ListValue policy_value;
962 InsertPrefValue(&policy_value, 0, extension1_->id());
963 InsertPrefValue(&policy_value, 1, extension2_->id());
964 InsertPrefValue(&policy_value, 2, extension3_->id());
965 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
966 policy_value.DeepCopy());
967 SetShelfChromeIconIndex(0);
968 // Model should only contain the browser shortcut and app list items.
969 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
970 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
971 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
972 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
974 // Installing |extension3_| should add it to the shelf - behind the
977 extension_service_->AddExtension(extension3_.get());
978 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
979 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
980 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
982 // Installing |extension2_| should add it to the launcher - behind the
983 // chrome icon, but in first location.
984 extension_service_->AddExtension(extension2_.get());
985 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
986 EXPECT_EQ("AppList, Chrome, App2, App3", GetPinnedAppStatus());
988 // Installing |extension1_| should add it to the launcher - behind the
989 // chrome icon, but in first location.
990 extension_service_->AddExtension(extension1_.get());
991 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
994 // Check that the restauration of launcher items is happening in the same order
995 // as the user has pinned them (on another system) when they are synced random
997 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrder) {
998 InitLauncherController();
1000 base::ListValue policy_value;
1001 InsertPrefValue(&policy_value, 0, extension1_->id());
1002 InsertPrefValue(&policy_value, 1, extension2_->id());
1003 InsertPrefValue(&policy_value, 2, extension3_->id());
1004 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1005 policy_value.DeepCopy());
1006 SetShelfChromeIconIndex(0);
1007 // Model should only contain the browser shortcut and app list items.
1008 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1009 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1010 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1011 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1013 // Installing |extension2_| should add it to the launcher - behind the
1015 extension_service_->AddExtension(extension2_.get());
1016 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1017 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1018 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1020 // Installing |extension1_| should add it to the launcher - behind the
1021 // chrome icon, but in first location.
1022 extension_service_->AddExtension(extension1_.get());
1023 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1024 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
1026 // Installing |extension3_| should add it to the launcher - behind the
1027 // chrome icon, but in first location.
1028 extension_service_->AddExtension(extension3_.get());
1029 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1032 // Check that the restauration of launcher items is happening in the same order
1033 // as the user has pinned / moved them (on another system) when they are synced
1034 // random order - including the chrome icon.
1035 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrderChromeMoved) {
1036 InitLauncherController();
1038 base::ListValue policy_value;
1039 InsertPrefValue(&policy_value, 0, extension1_->id());
1040 InsertPrefValue(&policy_value, 1, extension2_->id());
1041 InsertPrefValue(&policy_value, 2, extension3_->id());
1042 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1043 policy_value.DeepCopy());
1044 SetShelfChromeIconIndex(1);
1045 // Model should only contain the browser shortcut and app list items.
1046 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1047 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1048 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1049 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1051 // Installing |extension2_| should add it to the shelf - behind the
1053 ash::ShelfItem item;
1054 extension_service_->AddExtension(extension2_.get());
1055 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1056 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1057 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1059 // Installing |extension1_| should add it to the launcher - behind the
1060 // chrome icon, but in first location.
1061 extension_service_->AddExtension(extension1_.get());
1062 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1063 EXPECT_EQ("AppList, App1, Chrome, App2", GetPinnedAppStatus());
1065 // Installing |extension3_| should add it to the launcher - behind the
1066 // chrome icon, but in first location.
1067 extension_service_->AddExtension(extension3_.get());
1068 EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus());
1071 // Check that syncing to a different state does the correct thing.
1072 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsResyncOrder) {
1073 InitLauncherController();
1074 base::ListValue policy_value;
1075 InsertPrefValue(&policy_value, 0, extension1_->id());
1076 InsertPrefValue(&policy_value, 1, extension2_->id());
1077 InsertPrefValue(&policy_value, 2, extension3_->id());
1078 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1079 policy_value.DeepCopy());
1080 // The shelf layout has always one static item at the beginning (App List).
1081 SetShelfChromeIconIndex(0);
1082 extension_service_->AddExtension(extension2_.get());
1083 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1084 extension_service_->AddExtension(extension1_.get());
1085 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
1086 extension_service_->AddExtension(extension3_.get());
1087 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1089 // Change the order with increasing chrome position and decreasing position.
1090 base::ListValue policy_value1;
1091 InsertPrefValue(&policy_value1, 0, extension3_->id());
1092 InsertPrefValue(&policy_value1, 1, extension1_->id());
1093 InsertPrefValue(&policy_value1, 2, extension2_->id());
1094 SetShelfChromeIconIndex(3);
1095 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1096 policy_value1.DeepCopy());
1097 EXPECT_EQ("AppList, App3, App1, App2, Chrome", GetPinnedAppStatus());
1098 base::ListValue policy_value2;
1099 InsertPrefValue(&policy_value2, 0, extension2_->id());
1100 InsertPrefValue(&policy_value2, 1, extension3_->id());
1101 InsertPrefValue(&policy_value2, 2, extension1_->id());
1102 SetShelfChromeIconIndex(2);
1103 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1104 policy_value2.DeepCopy());
1105 EXPECT_EQ("AppList, App2, App3, Chrome, App1", GetPinnedAppStatus());
1107 // Check that the chrome icon can also be at the first possible location.
1108 SetShelfChromeIconIndex(0);
1109 base::ListValue policy_value3;
1110 InsertPrefValue(&policy_value3, 0, extension3_->id());
1111 InsertPrefValue(&policy_value3, 1, extension2_->id());
1112 InsertPrefValue(&policy_value3, 2, extension1_->id());
1113 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1114 policy_value3.DeepCopy());
1115 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1117 // Check that unloading of extensions works as expected.
1118 extension_service_->UnloadExtension(extension1_->id(),
1119 UnloadedExtensionInfo::REASON_UNINSTALL);
1120 EXPECT_EQ("AppList, Chrome, App3, App2", GetPinnedAppStatus());
1122 extension_service_->UnloadExtension(extension2_->id(),
1123 UnloadedExtensionInfo::REASON_UNINSTALL);
1124 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1126 // Check that an update of an extension does not crash the system.
1127 extension_service_->UnloadExtension(extension3_->id(),
1128 UnloadedExtensionInfo::REASON_UPDATE);
1129 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1132 // Check that simple locking of an application will 'create' a launcher item.
1133 TEST_F(ChromeLauncherControllerTest, CheckLockApps) {
1134 InitLauncherController();
1135 // Model should only contain the browser shortcut and app list items.
1136 EXPECT_EQ(2, model_->item_count());
1137 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1139 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1140 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1142 launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
1144 launcher_controller_->LockV1AppWithID(extension1_->id());
1146 EXPECT_EQ(3, model_->item_count());
1147 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1148 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1149 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1150 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1152 launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
1154 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1156 EXPECT_EQ(2, model_->item_count());
1157 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1159 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1160 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1162 launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
1165 // Check that multiple locks of an application will be properly handled.
1166 TEST_F(ChromeLauncherControllerTest, CheckMultiLockApps) {
1167 InitLauncherController();
1168 // Model should only contain the browser shortcut and app list items.
1169 EXPECT_EQ(2, model_->item_count());
1170 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1172 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1174 for (int i = 0; i < 2; i++) {
1175 launcher_controller_->LockV1AppWithID(extension1_->id());
1177 EXPECT_EQ(3, model_->item_count());
1178 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1179 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1180 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(
1181 extension1_->id()));
1184 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1186 EXPECT_EQ(3, model_->item_count());
1187 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1188 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1189 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1191 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1193 EXPECT_EQ(2, model_->item_count());
1194 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1196 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1197 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1199 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1202 // Check that already pinned items are not effected by locks.
1203 TEST_F(ChromeLauncherControllerTest, CheckAlreadyPinnedLockApps) {
1204 InitLauncherController();
1205 // Model should only contain the browser shortcut and app list items.
1206 EXPECT_EQ(2, model_->item_count());
1207 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1209 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1211 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1212 launcher_controller_->PinAppWithID(extension1_->id());
1213 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1215 EXPECT_EQ(3, model_->item_count());
1216 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1217 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1219 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1221 launcher_controller_->LockV1AppWithID(extension1_->id());
1223 EXPECT_EQ(3, model_->item_count());
1224 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1225 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1227 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1229 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1231 EXPECT_EQ(3, model_->item_count());
1232 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1233 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1235 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1237 launcher_controller_->UnpinAppWithID(extension1_->id());
1239 EXPECT_EQ(2, model_->item_count());
1242 // Check that already pinned items which get locked stay after unpinning.
1243 TEST_F(ChromeLauncherControllerTest, CheckPinnedAppsStayAfterUnlock) {
1244 InitLauncherController();
1245 // Model should only contain the browser shortcut and app list items.
1246 EXPECT_EQ(2, model_->item_count());
1247 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1249 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1251 launcher_controller_->PinAppWithID(extension1_->id());
1253 EXPECT_EQ(3, model_->item_count());
1254 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1255 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1257 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1259 launcher_controller_->LockV1AppWithID(extension1_->id());
1261 EXPECT_EQ(3, model_->item_count());
1262 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1263 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1265 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1267 launcher_controller_->UnpinAppWithID(extension1_->id());
1269 EXPECT_EQ(3, model_->item_count());
1270 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1271 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1272 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1274 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1276 EXPECT_EQ(2, model_->item_count());
1279 #if defined(OS_CHROMEOS)
1280 // Check that running applications wich are not pinned get properly restored
1281 // upon user change.
1282 TEST_F(ChromeLauncherControllerTest, CheckRunningAppOrder) {
1283 InitLauncherController();
1284 // Model should only contain the browser shortcut and app list items.
1285 EXPECT_EQ(2, model_->item_count());
1287 // Add a few running applications.
1288 launcher_controller_->LockV1AppWithID(extension1_->id());
1289 launcher_controller_->LockV1AppWithID(extension2_->id());
1290 launcher_controller_->LockV1AppWithID(extension3_->id());
1291 EXPECT_EQ(5, model_->item_count());
1292 // Note that this not only checks the order of applications but also the
1294 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
1296 // Remember the current order of applications for the current user.
1297 const std::string& current_user_id =
1298 multi_user_util::GetUserIDFromProfile(profile());
1299 RememberUnpinnedRunningApplicationOrder();
1301 // Switch some items and check that restoring a user which was not yet
1302 // remembered changes nothing.
1304 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
1305 RestoreUnpinnedRunningApplicationOrder("second-fake-user@fake.com");
1306 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
1308 // Restoring the stored user should however do the right thing.
1309 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1310 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
1312 // Switch again some items and even delete one - making sure that the missing
1313 // item gets properly handled.
1315 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1316 EXPECT_EQ("AppList, Chrome, app3, app2", GetPinnedAppStatus());
1317 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1318 EXPECT_EQ("AppList, Chrome, app2, app3", GetPinnedAppStatus());
1320 // Check that removing more items does not crash and changes nothing.
1321 launcher_controller_->UnlockV1AppWithID(extension2_->id());
1322 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1323 EXPECT_EQ("AppList, Chrome, app3", GetPinnedAppStatus());
1324 launcher_controller_->UnlockV1AppWithID(extension3_->id());
1325 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1326 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1329 // Check that with multi profile V1 apps are properly added / removed from the
1331 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1332 V1AppUpdateOnUserSwitch) {
1333 // Create a browser item in the LauncherController.
1334 InitLauncherController();
1335 EXPECT_EQ(2, model_->item_count());
1337 // Create a "windowed gmail app".
1338 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1339 profile(), extension_misc::kGmailAppId, gmail_url));
1340 EXPECT_EQ(3, model_->item_count());
1342 // After switching to a second user the item should be gone.
1343 std::string user2 = "user2";
1344 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1345 SwitchActiveUser(profile2->GetProfileName());
1346 EXPECT_EQ(2, model_->item_count());
1348 // After switching back the item should be back.
1349 SwitchActiveUser(profile()->GetProfileName());
1350 EXPECT_EQ(3, model_->item_count());
1351 // Note we destroy now the gmail app with the closure end.
1353 EXPECT_EQ(2, model_->item_count());
1356 // Check edge cases with multi profile V1 apps in the shelf.
1357 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1358 V1AppUpdateOnUserSwitchEdgecases) {
1359 // Create a browser item in the LauncherController.
1360 InitLauncherController();
1362 // First test: Create an app when the user is not active.
1363 std::string user2 = "user2";
1364 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1366 // Create a "windowed gmail app".
1367 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1368 profile2, extension_misc::kGmailAppId, gmail_url));
1369 EXPECT_EQ(2, model_->item_count());
1371 // However - switching to the user should show it.
1372 SwitchActiveUser(profile2->GetProfileName());
1373 EXPECT_EQ(3, model_->item_count());
1375 // Second test: Remove the app when the user is not active and see that it
1377 SwitchActiveUser(profile()->GetProfileName());
1378 EXPECT_EQ(2, model_->item_count());
1379 // Note: the closure ends and the browser will go away.
1381 EXPECT_EQ(2, model_->item_count());
1382 SwitchActiveUser(profile2->GetProfileName());
1383 EXPECT_EQ(2, model_->item_count());
1384 SwitchActiveUser(profile()->GetProfileName());
1385 EXPECT_EQ(2, model_->item_count());
1388 // Check edge case where a visiting V1 app gets closed (crbug.com/321374).
1389 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1390 V1CloseOnVisitingDesktop) {
1391 // Create a browser item in the LauncherController.
1392 InitLauncherController();
1394 chrome::MultiUserWindowManager* manager =
1395 chrome::MultiUserWindowManager::GetInstance();
1397 // First create an app when the user is active.
1398 std::string user2 = "user2";
1399 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1401 // Create a "windowed gmail app".
1402 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1404 extension_misc::kGmailAppId,
1406 EXPECT_EQ(3, model_->item_count());
1408 // Transfer the app to the other screen and switch users.
1409 manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(),
1411 EXPECT_EQ(3, model_->item_count());
1412 SwitchActiveUser(profile2->GetProfileName());
1413 EXPECT_EQ(2, model_->item_count());
1415 // After the app was destroyed, switch back. (which caused already a crash).
1416 SwitchActiveUser(profile()->GetProfileName());
1418 // Create the same app again - which was also causing the crash.
1419 EXPECT_EQ(2, model_->item_count());
1421 // Create a "windowed gmail app".
1422 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1424 extension_misc::kGmailAppId,
1426 EXPECT_EQ(3, model_->item_count());
1428 SwitchActiveUser(profile2->GetProfileName());
1429 EXPECT_EQ(2, model_->item_count());
1432 // Check edge cases with multi profile V1 apps in the shelf.
1433 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1434 V1AppUpdateOnUserSwitchEdgecases2) {
1435 // Create a browser item in the LauncherController.
1436 InitLauncherController();
1437 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
1438 SetAppTabHelper(app_tab_helper);
1440 // First test: Create an app when the user is not active.
1441 std::string user2 = "user2";
1442 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1443 SwitchActiveUser(profile2->GetProfileName());
1445 // Create a "windowed gmail app".
1446 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1447 profile(), extension_misc::kGmailAppId, gmail_url));
1448 EXPECT_EQ(2, model_->item_count());
1450 // However - switching to the user should show it.
1451 SwitchActiveUser(profile()->GetProfileName());
1452 EXPECT_EQ(3, model_->item_count());
1454 // Second test: Remove the app when the user is not active and see that it
1456 SwitchActiveUser(profile2->GetProfileName());
1457 EXPECT_EQ(2, model_->item_count());
1460 EXPECT_EQ(2, model_->item_count());
1461 SwitchActiveUser(profile()->GetProfileName());
1462 EXPECT_EQ(2, model_->item_count());
1463 SwitchActiveUser(profile2->GetProfileName());
1464 EXPECT_EQ(2, model_->item_count());
1467 // Check that activating an item which is on another user's desktop, will bring
1469 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1470 TestLauncherActivationPullsBackWindow) {
1471 // Create a browser item in the LauncherController.
1472 InitLauncherController();
1473 chrome::MultiUserWindowManager* manager =
1474 chrome::MultiUserWindowManager::GetInstance();
1476 // Add two users to the window manager.
1477 std::string user2 = "user2";
1478 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1479 manager->AddUser(profile());
1480 manager->AddUser(profile2);
1481 const std::string& current_user =
1482 multi_user_util::GetUserIDFromProfile(profile());
1484 // Create a browser window with a native window for the current user.
1485 scoped_ptr<BrowserWindow> browser_window(CreateTestBrowserWindow(
1486 Browser::CreateParams(profile(), chrome::HOST_DESKTOP_TYPE_ASH)));
1487 aura::Window* window = browser_window->GetNativeWindow();
1488 manager->SetWindowOwner(window, current_user);
1490 // Check that an activation of the window on its owner's desktop does not
1491 // change the visibility to another user.
1492 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window.get(),
1494 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
1496 // Transfer the window to another user's desktop and check that activating it
1497 // does pull it back to that user.
1498 manager->ShowWindowForUser(window, user2);
1499 EXPECT_FALSE(manager->IsWindowOnDesktopOfUser(window, current_user));
1500 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window.get(),
1502 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
1506 // Check that lock -> pin -> unlock -> unpin does properly transition.
1507 TEST_F(ChromeLauncherControllerTest, CheckLockPinUnlockUnpin) {
1508 InitLauncherController();
1509 // Model should only contain the browser shortcut and app list items.
1510 EXPECT_EQ(2, model_->item_count());
1511 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1513 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1515 launcher_controller_->LockV1AppWithID(extension1_->id());
1517 EXPECT_EQ(3, model_->item_count());
1518 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1519 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1520 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1522 launcher_controller_->PinAppWithID(extension1_->id());
1524 EXPECT_EQ(3, model_->item_count());
1525 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1526 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1528 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1530 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1532 EXPECT_EQ(3, model_->item_count());
1533 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1534 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1536 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1538 launcher_controller_->UnpinAppWithID(extension1_->id());
1540 EXPECT_EQ(2, model_->item_count());
1543 // Check that a locked (windowed V1 application) will be properly converted
1544 // between locked and pinned when the order gets changed through a profile /
1546 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAndLockedAppsResyncOrder) {
1547 InitLauncherController();
1548 base::ListValue policy_value0;
1549 InsertPrefValue(&policy_value0, 0, extension1_->id());
1550 InsertPrefValue(&policy_value0, 1, extension3_->id());
1551 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1552 policy_value0.DeepCopy());
1553 // The shelf layout has always one static item at the beginning (App List).
1554 SetShelfChromeIconIndex(0);
1555 extension_service_->AddExtension(extension1_.get());
1556 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1557 extension_service_->AddExtension(extension2_.get());
1558 // No new app icon will be generated.
1559 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1560 // Add the app as locked app which will add it (un-pinned).
1561 launcher_controller_->LockV1AppWithID(extension2_->id());
1562 EXPECT_EQ("AppList, Chrome, App1, app2", GetPinnedAppStatus());
1563 extension_service_->AddExtension(extension3_.get());
1564 EXPECT_EQ("AppList, Chrome, App1, App3, app2", GetPinnedAppStatus());
1566 // Now request to pin all items which should convert the locked item into a
1568 base::ListValue policy_value1;
1569 InsertPrefValue(&policy_value1, 0, extension3_->id());
1570 InsertPrefValue(&policy_value1, 1, extension2_->id());
1571 InsertPrefValue(&policy_value1, 2, extension1_->id());
1572 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1573 policy_value1.DeepCopy());
1574 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1576 // Going back to a status where there is no requirement for app 2 to be pinned
1577 // should convert it back to locked but not pinned and state. The position
1578 // is determined by the |ShelfModel|'s weight system and since running
1579 // applications are not allowed to be mixed with shortcuts, it should show up
1580 // at the end of the list.
1581 base::ListValue policy_value2;
1582 InsertPrefValue(&policy_value2, 0, extension3_->id());
1583 InsertPrefValue(&policy_value2, 1, extension1_->id());
1584 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1585 policy_value2.DeepCopy());
1586 EXPECT_EQ("AppList, Chrome, App3, App1, app2", GetPinnedAppStatus());
1588 // Removing an item should simply close it and everything should shift.
1589 base::ListValue policy_value3;
1590 InsertPrefValue(&policy_value3, 0, extension3_->id());
1591 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1592 policy_value3.DeepCopy());
1593 EXPECT_EQ("AppList, Chrome, App3, app2", GetPinnedAppStatus());
1596 // Check that a running and not pinned V2 application will be properly converted
1597 // between locked and pinned when the order gets changed through a profile /
1599 TEST_F(ChromeLauncherControllerTest,
1600 RestoreDefaultAndRunningV2AppsResyncOrder) {
1601 InitLauncherController();
1602 base::ListValue policy_value0;
1603 InsertPrefValue(&policy_value0, 0, extension1_->id());
1604 InsertPrefValue(&policy_value0, 1, extension3_->id());
1605 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1606 policy_value0.DeepCopy());
1607 // The shelf layout has always one static item at the beginning (app List).
1608 SetShelfChromeIconIndex(0);
1609 extension_service_->AddExtension(extension1_.get());
1610 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1611 extension_service_->AddExtension(extension2_.get());
1612 // No new app icon will be generated.
1613 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1614 // Add the app as an unpinned but running V2 app.
1615 CreateRunningV2App(extension2_->id());
1616 EXPECT_EQ("AppList, Chrome, App1, *app2", GetPinnedAppStatus());
1617 extension_service_->AddExtension(extension3_.get());
1618 EXPECT_EQ("AppList, Chrome, App1, App3, *app2", GetPinnedAppStatus());
1620 // Now request to pin all items which should convert the locked item into a
1622 base::ListValue policy_value1;
1623 InsertPrefValue(&policy_value1, 0, extension3_->id());
1624 InsertPrefValue(&policy_value1, 1, extension2_->id());
1625 InsertPrefValue(&policy_value1, 2, extension1_->id());
1626 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1627 policy_value1.DeepCopy());
1628 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1630 // Going back to a status where there is no requirement for app 2 to be pinned
1631 // should convert it back to running V2 app. Since the position is determined
1632 // by the |ShelfModel|'s weight system, it will be after last pinned item.
1633 base::ListValue policy_value2;
1634 InsertPrefValue(&policy_value2, 0, extension3_->id());
1635 InsertPrefValue(&policy_value2, 1, extension1_->id());
1636 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1637 policy_value2.DeepCopy());
1638 EXPECT_EQ("AppList, Chrome, App3, App1, *app2", GetPinnedAppStatus());
1640 // Removing an item should simply close it and everything should shift.
1641 base::ListValue policy_value3;
1642 InsertPrefValue(&policy_value3, 0, extension3_->id());
1643 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1644 policy_value3.DeepCopy());
1645 EXPECT_EQ("AppList, Chrome, App3, *app2", GetPinnedAppStatus());
1648 // Each user has a different set of applications pinned. Check that when
1649 // switching between the two users, the state gets properly set.
1650 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestore) {
1651 base::ListValue user_a;
1652 base::ListValue user_b;
1653 SetUpMultiUserScenario(&user_a, &user_b);
1655 SetShelfChromeIconIndex(6);
1656 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1658 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1659 GetPinnedAppStatus());
1662 SetShelfChromeIconIndex(4);
1663 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1666 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus());
1668 // Switch back to 1.
1669 SetShelfChromeIconIndex(8);
1670 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1672 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1673 GetPinnedAppStatus());
1675 // Switch back to 2.
1676 SetShelfChromeIconIndex(4);
1677 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1679 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus());
1682 // Each user has a different set of applications pinned, and one user has an
1683 // application running. Check that when switching between the two users, the
1684 // state gets properly set.
1685 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestoreWithRunningV2App) {
1686 base::ListValue user_a;
1687 base::ListValue user_b;
1688 SetUpMultiUserScenario(&user_a, &user_b);
1690 // Run App1 and assume that it is a V2 app.
1691 CreateRunningV2App(extension1_->id());
1694 SetShelfChromeIconIndex(6);
1695 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1697 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1698 GetPinnedAppStatus());
1701 SetShelfChromeIconIndex(4);
1702 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1705 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus());
1707 // Switch back to 1.
1708 SetShelfChromeIconIndex(8);
1709 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1711 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1712 GetPinnedAppStatus());
1714 // Switch back to 2.
1715 SetShelfChromeIconIndex(4);
1716 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1718 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus());
1721 // Each user has a different set of applications pinned, and one user has an
1722 // application running. The chrome icon is not the last item in the list.
1723 // Check that when switching between the two users, the state gets properly set.
1724 // There was once a bug associated with this.
1725 TEST_F(ChromeLauncherControllerTest,
1726 UserSwitchIconRestoreWithRunningV2AppChromeInMiddle) {
1727 base::ListValue user_a;
1728 base::ListValue user_b;
1729 SetUpMultiUserScenario(&user_a, &user_b);
1731 // Run App1 and assume that it is a V2 app.
1732 CreateRunningV2App(extension1_->id());
1735 SetShelfChromeIconIndex(5);
1736 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1738 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6",
1739 GetPinnedAppStatus());
1742 SetShelfChromeIconIndex(4);
1743 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1746 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus());
1748 // Switch back to 1.
1749 SetShelfChromeIconIndex(5);
1750 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1752 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6",
1753 GetPinnedAppStatus());
1756 TEST_F(ChromeLauncherControllerTest, Policy) {
1757 extension_service_->AddExtension(extension1_.get());
1758 extension_service_->AddExtension(extension3_.get());
1760 base::ListValue policy_value;
1761 InsertPrefValue(&policy_value, 0, extension1_->id());
1762 InsertPrefValue(&policy_value, 1, extension2_->id());
1763 profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
1764 policy_value.DeepCopy());
1766 // Only |extension1_| should get pinned. |extension2_| is specified but not
1767 // installed, and |extension3_| is part of the default set, but that shouldn't
1768 // take effect when the policy override is in place.
1769 InitLauncherController();
1770 EXPECT_EQ(3, model_->item_count());
1771 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1772 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1773 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1774 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1776 // Installing |extension2_| should add it to the launcher.
1777 extension_service_->AddExtension(extension2_.get());
1778 EXPECT_EQ(4, model_->item_count());
1779 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1780 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[3].type);
1781 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1782 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1783 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1785 // Removing |extension1_| from the policy should be reflected in the launcher.
1786 policy_value.Remove(0, NULL);
1787 profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
1788 policy_value.DeepCopy());
1789 EXPECT_EQ(3, model_->item_count());
1790 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1791 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1792 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1793 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1796 TEST_F(ChromeLauncherControllerTest, UnpinWithUninstall) {
1797 extension_service_->AddExtension(extension3_.get());
1798 extension_service_->AddExtension(extension4_.get());
1800 InitLauncherController();
1802 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1803 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
1805 extension_service_->UnloadExtension(extension3_->id(),
1806 UnloadedExtensionInfo::REASON_UNINSTALL);
1808 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1809 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
1812 TEST_F(ChromeLauncherControllerTest, PrefUpdates) {
1813 extension_service_->AddExtension(extension2_.get());
1814 extension_service_->AddExtension(extension3_.get());
1815 extension_service_->AddExtension(extension4_.get());
1817 InitLauncherController();
1819 std::vector<std::string> expected_launchers;
1820 std::vector<std::string> actual_launchers;
1821 base::ListValue pref_value;
1822 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1823 pref_value.DeepCopy());
1824 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1825 EXPECT_EQ(expected_launchers, actual_launchers);
1827 // Unavailable extensions don't create launcher items.
1828 InsertPrefValue(&pref_value, 0, extension1_->id());
1829 InsertPrefValue(&pref_value, 1, extension2_->id());
1830 InsertPrefValue(&pref_value, 2, extension4_->id());
1831 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1832 pref_value.DeepCopy());
1833 expected_launchers.push_back(extension2_->id());
1834 expected_launchers.push_back(extension4_->id());
1835 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1836 EXPECT_EQ(expected_launchers, actual_launchers);
1838 // Redundant pref entries show up only once.
1839 InsertPrefValue(&pref_value, 2, extension3_->id());
1840 InsertPrefValue(&pref_value, 2, extension3_->id());
1841 InsertPrefValue(&pref_value, 5, extension3_->id());
1842 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1843 pref_value.DeepCopy());
1844 expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id());
1845 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1846 EXPECT_EQ(expected_launchers, actual_launchers);
1848 // Order changes are reflected correctly.
1850 InsertPrefValue(&pref_value, 0, extension4_->id());
1851 InsertPrefValue(&pref_value, 1, extension3_->id());
1852 InsertPrefValue(&pref_value, 2, extension2_->id());
1853 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1854 pref_value.DeepCopy());
1855 std::reverse(expected_launchers.begin(), expected_launchers.end());
1856 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1857 EXPECT_EQ(expected_launchers, actual_launchers);
1861 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1862 pref_value.DeepCopy());
1863 expected_launchers.clear();
1864 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1865 EXPECT_EQ(expected_launchers, actual_launchers);
1868 TEST_F(ChromeLauncherControllerTest, PendingInsertionOrder) {
1869 extension_service_->AddExtension(extension1_.get());
1870 extension_service_->AddExtension(extension3_.get());
1872 InitLauncherController();
1874 base::ListValue pref_value;
1875 InsertPrefValue(&pref_value, 0, extension1_->id());
1876 InsertPrefValue(&pref_value, 1, extension2_->id());
1877 InsertPrefValue(&pref_value, 2, extension3_->id());
1878 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1879 pref_value.DeepCopy());
1881 std::vector<std::string> expected_launchers;
1882 expected_launchers.push_back(extension1_->id());
1883 expected_launchers.push_back(extension3_->id());
1884 std::vector<std::string> actual_launchers;
1886 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1887 EXPECT_EQ(expected_launchers, actual_launchers);
1889 // Install |extension2| and verify it shows up between the other two.
1890 extension_service_->AddExtension(extension2_.get());
1891 expected_launchers.insert(expected_launchers.begin() + 1, extension2_->id());
1892 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1893 EXPECT_EQ(expected_launchers, actual_launchers);
1896 // Checks the created menus and menu lists for correctness. It uses the given
1897 // |controller| to create the objects for the given |item| and checks the
1898 // found item count against the |expected_items|. The |title| list contains the
1899 // menu titles in the order of their appearance in the menu (not including the
1900 // application name).
1901 bool CheckMenuCreation(ChromeLauncherController* controller,
1902 const ash::ShelfItem& item,
1903 size_t expected_items,
1904 base::string16 title[],
1906 ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0);
1907 // A new behavior has been added: Only show menus if there is at least one
1909 if (expected_items < 1 && is_browser) {
1910 EXPECT_EQ(0u, items.size());
1911 return items.size() == 0;
1913 // There should be one item in there: The title.
1914 EXPECT_EQ(expected_items + 1, items.size());
1915 EXPECT_FALSE(items[0]->IsEnabled());
1916 for (size_t i = 0; i < expected_items; i++) {
1917 EXPECT_EQ(title[i], items[1 + i]->title());
1918 // Check that the first real item has a leading separator.
1920 EXPECT_TRUE(items[i]->HasLeadingSeparator());
1922 EXPECT_FALSE(items[i]->HasLeadingSeparator());
1925 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel(
1926 controller->GetApplicationList(item, 0)));
1927 // The first element in the menu is a spacing separator. On some systems
1928 // (e.g. Windows) such things do not exist. As such we check the existence
1929 // and adjust dynamically.
1930 int first_item = menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR ? 1 : 0;
1931 int expected_menu_items = first_item +
1932 (expected_items ? (expected_items + 3) : 2);
1933 EXPECT_EQ(expected_menu_items, menu->GetItemCount());
1934 EXPECT_FALSE(menu->IsEnabledAt(first_item));
1935 if (expected_items) {
1936 EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR,
1937 menu->GetTypeAt(first_item + 1));
1939 return items.size() == expected_items + 1;
1942 // Check that browsers get reflected correctly in the launcher menu.
1943 TEST_F(ChromeLauncherControllerTest, BrowserMenuGeneration) {
1944 EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
1945 chrome::NewTab(browser());
1947 InitLauncherController();
1949 // Check that the browser list is empty at this time.
1950 ash::ShelfItem item_browser;
1951 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
1953 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
1954 EXPECT_TRUE(CheckMenuCreation(
1955 launcher_controller_.get(), item_browser, 0, NULL, true));
1957 // Now make the created browser() visible by adding it to the active browser
1959 BrowserList::SetLastActive(browser());
1960 base::string16 title1 = ASCIIToUTF16("Test1");
1961 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
1962 base::string16 one_menu_item[] = { title1 };
1964 EXPECT_TRUE(CheckMenuCreation(
1965 launcher_controller_.get(), item_browser, 1, one_menu_item, true));
1967 // Create one more browser/window and check that one more was added.
1968 Browser::CreateParams ash_params(profile(), chrome::HOST_DESKTOP_TYPE_ASH);
1969 scoped_ptr<Browser> browser2(
1970 chrome::CreateBrowserWithTestWindowForParams(&ash_params));
1971 chrome::NewTab(browser2.get());
1972 BrowserList::SetLastActive(browser2.get());
1973 base::string16 title2 = ASCIIToUTF16("Test2");
1974 NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
1977 // Check that the list contains now two entries - make furthermore sure that
1978 // the active item is the first entry.
1979 base::string16 two_menu_items[] = {title1, title2};
1980 EXPECT_TRUE(CheckMenuCreation(
1981 launcher_controller_.get(), item_browser, 2, two_menu_items, true));
1983 // Apparently we have to close all tabs we have.
1984 chrome::CloseTab(browser2.get());
1987 #if defined(OS_CHROMEOS)
1988 // Check the multi profile case where only user related browsers should show
1990 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1991 BrowserMenuGenerationTwoUsers) {
1992 // Create a browser item in the LauncherController.
1993 InitLauncherController();
1995 ash::ShelfItem item_browser;
1996 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
1998 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2000 // Check that the menu is empty.
2001 chrome::NewTab(browser());
2002 EXPECT_TRUE(CheckMenuCreation(
2003 launcher_controller_.get(), item_browser, 0, NULL, true));
2005 // Show the created |browser()| by adding it to the active browser list.
2006 BrowserList::SetLastActive(browser());
2007 base::string16 title1 = ASCIIToUTF16("Test1");
2008 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
2009 base::string16 one_menu_item1[] = { title1 };
2010 EXPECT_TRUE(CheckMenuCreation(
2011 launcher_controller_.get(), item_browser, 1, one_menu_item1, true));
2013 // Create a browser for another user and check that it is not included in the
2014 // users running browser list.
2015 std::string user2 = "user2";
2016 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2017 scoped_ptr<Browser> browser2(
2018 CreateBrowserAndTabWithProfile(profile2, user2, "http://test2"));
2019 base::string16 one_menu_item2[] = { ASCIIToUTF16(user2) };
2020 EXPECT_TRUE(CheckMenuCreation(
2021 launcher_controller_.get(), item_browser, 1, one_menu_item1, true));
2023 // Switch to the other user and make sure that only that browser window gets
2025 SwitchActiveUser(profile2->GetProfileName());
2026 EXPECT_TRUE(CheckMenuCreation(
2027 launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
2029 // Transferred browsers of other users should not show up in the list.
2030 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
2031 browser()->window()->GetNativeWindow(),
2033 EXPECT_TRUE(CheckMenuCreation(
2034 launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
2036 chrome::CloseTab(browser2.get());
2038 #endif // defined(OS_CHROMEOS)
2040 // Check that V1 apps are correctly reflected in the launcher menu using the
2042 // Note that the extension matching logic is tested by the extension system
2043 // and does not need a separate test here.
2044 TEST_F(ChromeLauncherControllerTest, V1AppMenuGeneration) {
2045 EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
2046 EXPECT_EQ(0, browser()->tab_strip_model()->count());
2048 InitLauncherControllerWithBrowser();
2050 // Model should only contain the browser shortcut and app list items.
2051 EXPECT_EQ(2, model_->item_count());
2052 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
2054 // Installing |extension3_| adds it to the launcher.
2055 ash::ShelfID gmail_id = model_->next_id();
2056 extension_service_->AddExtension(extension3_.get());
2057 EXPECT_EQ(3, model_->item_count());
2058 int gmail_index = model_->ItemIndexByID(gmail_id);
2059 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2060 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2061 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2063 // Check the menu content.
2064 ash::ShelfItem item_browser;
2065 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2067 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2069 ash::ShelfItem item_gmail;
2070 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2071 item_gmail.id = gmail_id;
2072 EXPECT_TRUE(CheckMenuCreation(
2073 launcher_controller_.get(), item_gmail, 0, NULL, false));
2075 // Set the gmail URL to a new tab.
2076 base::string16 title1 = ASCIIToUTF16("Test1");
2077 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2079 base::string16 one_menu_item[] = { title1 };
2080 EXPECT_TRUE(CheckMenuCreation(
2081 launcher_controller_.get(), item_gmail, 1, one_menu_item, false));
2083 // Create one empty tab.
2084 chrome::NewTab(browser());
2085 base::string16 title2 = ASCIIToUTF16("Test2");
2086 NavigateAndCommitActiveTabWithTitle(
2088 GURL("https://bla"),
2091 // and another one with another gmail instance.
2092 chrome::NewTab(browser());
2093 base::string16 title3 = ASCIIToUTF16("Test3");
2094 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3);
2095 base::string16 two_menu_items[] = {title1, title3};
2096 EXPECT_TRUE(CheckMenuCreation(
2097 launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
2099 // Even though the item is in the V1 app list, it should also be in the
2101 base::string16 browser_menu_item[] = {title3};
2102 EXPECT_TRUE(CheckMenuCreation(
2103 launcher_controller_.get(), item_browser, 1, browser_menu_item, false));
2105 // Test that closing of (all) the item(s) does work (and all menus get
2106 // updated properly).
2107 launcher_controller_->Close(item_gmail.id);
2109 EXPECT_TRUE(CheckMenuCreation(
2110 launcher_controller_.get(), item_gmail, 0, NULL, false));
2111 base::string16 browser_menu_item2[] = { title2 };
2112 EXPECT_TRUE(CheckMenuCreation(
2113 launcher_controller_.get(), item_browser, 1, browser_menu_item2, false));
2116 #if defined(OS_CHROMEOS)
2117 // Check the multi profile case where only user related apps should show up.
2118 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2119 V1AppMenuGenerationTwoUsers) {
2120 // Create a browser item in the LauncherController.
2121 InitLauncherController();
2122 chrome::NewTab(browser());
2124 // Installing |extension3_| adds it to the launcher.
2125 ash::ShelfID gmail_id = model_->next_id();
2126 extension_service_->AddExtension(extension3_.get());
2127 EXPECT_EQ(3, model_->item_count());
2128 int gmail_index = model_->ItemIndexByID(gmail_id);
2129 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2130 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2131 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2133 // Check the menu content.
2134 ash::ShelfItem item_browser;
2135 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2137 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2139 ash::ShelfItem item_gmail;
2140 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2141 item_gmail.id = gmail_id;
2142 EXPECT_TRUE(CheckMenuCreation(
2143 launcher_controller_.get(), item_gmail, 0, NULL, false));
2145 // Set the gmail URL to a new tab.
2146 base::string16 title1 = ASCIIToUTF16("Test1");
2147 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2149 base::string16 one_menu_item[] = { title1 };
2150 EXPECT_TRUE(CheckMenuCreation(
2151 launcher_controller_.get(), item_gmail, 1, one_menu_item, false));
2153 // Create a second profile and switch to that user.
2154 std::string user2 = "user2";
2155 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2156 SwitchActiveUser(profile2->GetProfileName());
2158 // No item should have content yet.
2159 EXPECT_TRUE(CheckMenuCreation(
2160 launcher_controller_.get(), item_browser, 0, NULL, true));
2161 EXPECT_TRUE(CheckMenuCreation(
2162 launcher_controller_.get(), item_gmail, 0, NULL, false));
2164 // Transfer the browser of the first user - it should still not show up.
2165 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
2166 browser()->window()->GetNativeWindow(),
2169 EXPECT_TRUE(CheckMenuCreation(
2170 launcher_controller_.get(), item_browser, 0, NULL, true));
2171 EXPECT_TRUE(CheckMenuCreation(
2172 launcher_controller_.get(), item_gmail, 0, NULL, false));
2175 // Check that V2 applications are creating items properly in the launcher when
2176 // instantiated by the current user.
2177 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2178 V2AppHandlingTwoUsers) {
2179 InitLauncherController();
2180 // Create a profile for our second user (will be destroyed by the framework).
2181 TestingProfile* profile2 = CreateMultiUserProfile("user2");
2182 // Check that there is a browser and a app launcher.
2183 EXPECT_EQ(2, model_->item_count());
2186 V2App v2_app(profile(), extension1_.get());
2187 EXPECT_EQ(3, model_->item_count());
2189 // After switching users the item should go away.
2190 SwitchActiveUser(profile2->GetProfileName());
2191 EXPECT_EQ(2, model_->item_count());
2193 // And it should come back when switching back.
2194 SwitchActiveUser(profile()->GetProfileName());
2195 EXPECT_EQ(3, model_->item_count());
2198 // Check that V2 applications are creating items properly in edge cases:
2199 // a background user creates a V2 app, gets active and inactive again and then
2201 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2202 V2AppHandlingTwoUsersEdgeCases) {
2203 InitLauncherController();
2204 // Create a profile for our second user (will be destroyed by the framework).
2205 TestingProfile* profile2 = CreateMultiUserProfile("user2");
2206 // Check that there is a browser and a app launcher.
2207 EXPECT_EQ(2, model_->item_count());
2209 // Switch to an inactive user.
2210 SwitchActiveUser(profile2->GetProfileName());
2211 EXPECT_EQ(2, model_->item_count());
2213 // Add the v2 app to the inactive user and check that no item was added to
2216 V2App v2_app(profile(), extension1_.get());
2217 EXPECT_EQ(2, model_->item_count());
2219 // Switch to the primary user and check that the item is shown.
2220 SwitchActiveUser(profile()->GetProfileName());
2221 EXPECT_EQ(3, model_->item_count());
2223 // Switch to the second user and check that the item goes away - even if the
2224 // item gets closed.
2225 SwitchActiveUser(profile2->GetProfileName());
2226 EXPECT_EQ(2, model_->item_count());
2229 // After the application was killed there should be still 2 items.
2230 EXPECT_EQ(2, model_->item_count());
2232 // Switching then back to the default user should not show the additional item
2234 SwitchActiveUser(profile()->GetProfileName());
2235 EXPECT_EQ(2, model_->item_count());
2238 // Check that V2 applications will be made visible on the target desktop if
2239 // another window of the same type got previously teleported there.
2240 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2241 V2AppFollowsTeleportedWindow) {
2242 InitLauncherController();
2243 chrome::MultiUserWindowManager* manager =
2244 chrome::MultiUserWindowManager::GetInstance();
2246 // Create and add three users / profiles, and go to #1's desktop.
2247 TestingProfile* profile1 = CreateMultiUserProfile("user-1");
2248 TestingProfile* profile2 = CreateMultiUserProfile("user-2");
2249 TestingProfile* profile3 = CreateMultiUserProfile("user-3");
2250 SwitchActiveUser(profile1->GetProfileName());
2252 // A v2 app for user #1 should be shown first and get hidden when switching to
2254 V2App v2_app_1(profile1, extension1_.get());
2255 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2256 SwitchActiveUser(profile2->GetProfileName());
2257 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2259 // Add a v2 app for user #1 while on desktop #2 should not be shown.
2260 V2App v2_app_2(profile1, extension1_.get());
2261 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2262 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2264 // Teleport the app from user #1 to the desktop #2 should show it.
2265 manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(),
2266 profile2->GetProfileName());
2267 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2268 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2270 // Creating a new application for user #1 on desktop #2 should teleport it
2271 // there automatically.
2272 V2App v2_app_3(profile1, extension1_.get());
2273 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2274 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2275 EXPECT_TRUE(v2_app_3.window()->GetNativeWindow()->IsVisible());
2277 // Switching back to desktop#1 and creating an app for user #1 should move
2278 // the app on desktop #1.
2279 SwitchActiveUser(profile1->GetProfileName());
2280 V2App v2_app_4(profile1, extension1_.get());
2281 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2282 EXPECT_TRUE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2283 EXPECT_FALSE(v2_app_3.window()->GetNativeWindow()->IsVisible());
2284 EXPECT_TRUE(v2_app_4.window()->GetNativeWindow()->IsVisible());
2286 // Switching to desktop #3 and create an app for user #1 there should land on
2287 // his own desktop (#1).
2288 SwitchActiveUser(profile3->GetProfileName());
2289 V2App v2_app_5(profile1, extension1_.get());
2290 EXPECT_FALSE(v2_app_5.window()->GetNativeWindow()->IsVisible());
2291 SwitchActiveUser(profile1->GetProfileName());
2292 EXPECT_TRUE(v2_app_5.window()->GetNativeWindow()->IsVisible());
2294 // Switching to desktop #2, hiding the app window and creating an app should
2295 // teleport there automatically.
2296 SwitchActiveUser(profile2->GetProfileName());
2297 v2_app_1.window()->Hide();
2298 V2App v2_app_6(profile1, extension1_.get());
2299 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2300 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2301 EXPECT_TRUE(v2_app_6.window()->GetNativeWindow()->IsVisible());
2304 // Check that V2 applications hide correctly on the shelf when the app window
2306 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2307 V2AppHiddenWindows) {
2308 InitLauncherController();
2310 TestingProfile* profile2 = CreateMultiUserProfile("user-2");
2311 SwitchActiveUser(profile()->GetProfileName());
2312 EXPECT_EQ(2, model_->item_count());
2314 V2App v2_app_1(profile(), extension1_.get());
2315 EXPECT_EQ(3, model_->item_count());
2317 // Hide and show the app.
2318 v2_app_1.window()->Hide();
2319 EXPECT_EQ(2, model_->item_count());
2321 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
2322 EXPECT_EQ(3, model_->item_count());
2325 // Switch user, hide and show the app and switch back.
2326 SwitchActiveUser(profile2->GetProfileName());
2327 EXPECT_EQ(2, model_->item_count());
2329 v2_app_1.window()->Hide();
2330 EXPECT_EQ(2, model_->item_count());
2332 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
2333 EXPECT_EQ(2, model_->item_count());
2335 SwitchActiveUser(profile()->GetProfileName());
2336 EXPECT_EQ(3, model_->item_count());
2339 // Switch user, hide the app, switch back and then show it again.
2340 SwitchActiveUser(profile2->GetProfileName());
2341 EXPECT_EQ(2, model_->item_count());
2343 v2_app_1.window()->Hide();
2344 EXPECT_EQ(2, model_->item_count());
2346 SwitchActiveUser(profile()->GetProfileName());
2347 EXPECT_EQ(2, model_->item_count());
2349 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
2350 EXPECT_EQ(3, model_->item_count());
2353 // Create a second app, hide and show it and then hide both apps.
2354 V2App v2_app_2(profile(), extension1_.get());
2355 EXPECT_EQ(3, model_->item_count());
2357 v2_app_2.window()->Hide();
2358 EXPECT_EQ(3, model_->item_count());
2360 v2_app_2.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
2361 EXPECT_EQ(3, model_->item_count());
2363 v2_app_1.window()->Hide();
2364 v2_app_2.window()->Hide();
2365 EXPECT_EQ(2, model_->item_count());
2368 #endif // defined(OS_CHROMEOS)
2370 // Checks that the generated menu list properly activates items.
2371 TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) {
2372 InitLauncherControllerWithBrowser();
2374 // Add |extension3_| to the launcher and add two items.
2375 GURL gmail = GURL("https://mail.google.com/mail/u");
2376 ash::ShelfID gmail_id = model_->next_id();
2377 extension_service_->AddExtension(extension3_.get());
2378 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2379 base::string16 title1 = ASCIIToUTF16("Test1");
2380 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2381 chrome::NewTab(browser());
2382 base::string16 title2 = ASCIIToUTF16("Test2");
2383 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
2385 // Check that the menu is properly set.
2386 ash::ShelfItem item_gmail;
2387 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2388 item_gmail.id = gmail_id;
2389 base::string16 two_menu_items[] = {title1, title2};
2390 EXPECT_TRUE(CheckMenuCreation(
2391 launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
2392 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
2393 // Execute the second item in the list (which shouldn't do anything since that
2394 // item is per definition already the active tab).
2396 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel(
2397 launcher_controller_->GetApplicationList(item_gmail, 0)));
2398 // The first element in the menu is a spacing separator. On some systems
2399 // (e.g. Windows) such things do not exist. As such we check the existence
2400 // and adjust dynamically.
2402 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
2403 menu->ActivatedAt(first_item + 3);
2405 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
2407 // Execute the first item.
2409 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel(
2410 launcher_controller_->GetApplicationList(item_gmail, 0)));
2412 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
2413 menu->ActivatedAt(first_item + 2);
2415 // Now the active tab should be the second item.
2416 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
2419 // Checks that the generated menu list properly deletes items.
2420 TEST_F(ChromeLauncherControllerTest, V1AppMenuDeletionExecution) {
2421 InitLauncherControllerWithBrowser();
2423 // Add |extension3_| to the launcher and add two items.
2424 GURL gmail = GURL("https://mail.google.com/mail/u");
2425 ash::ShelfID gmail_id = model_->next_id();
2426 extension_service_->AddExtension(extension3_.get());
2427 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2428 base::string16 title1 = ASCIIToUTF16("Test1");
2429 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2430 chrome::NewTab(browser());
2431 base::string16 title2 = ASCIIToUTF16("Test2");
2432 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
2434 // Check that the menu is properly set.
2435 ash::ShelfItem item_gmail;
2436 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2437 item_gmail.id = gmail_id;
2438 base::string16 two_menu_items[] = {title1, title2};
2439 EXPECT_TRUE(CheckMenuCreation(
2440 launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
2442 int tabs = browser()->tab_strip_model()->count();
2443 // Activate the proper tab through the menu item.
2445 ChromeLauncherAppMenuItems items =
2446 launcher_controller_->GetApplicationList(item_gmail, 0);
2447 items[1]->Execute(0);
2448 EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
2451 // Delete one tab through the menu item.
2453 ChromeLauncherAppMenuItems items =
2454 launcher_controller_->GetApplicationList(item_gmail, 0);
2455 items[1]->Execute(ui::EF_SHIFT_DOWN);
2456 EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
2460 // Tests that panels create launcher items correctly
2461 TEST_F(ChromeLauncherControllerTest, AppPanels) {
2462 InitLauncherControllerWithBrowser();
2463 // App list and Browser shortcut ShelfItems are added.
2464 EXPECT_EQ(2, model_observer_->added());
2466 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl();
2467 SetAppIconLoader(app_icon_loader);
2469 // Test adding an app panel
2470 std::string app_id = extension1_->id();
2471 AppWindowLauncherItemController* app_panel_controller =
2472 new AppWindowLauncherItemController(
2473 LauncherItemController::TYPE_APP_PANEL,
2476 launcher_controller_.get());
2477 ash::ShelfID shelf_id1 = launcher_controller_->CreateAppLauncherItem(
2478 app_panel_controller, app_id, ash::STATUS_RUNNING);
2479 int panel_index = model_observer_->last_index();
2480 EXPECT_EQ(3, model_observer_->added());
2481 EXPECT_EQ(0, model_observer_->changed());
2482 EXPECT_EQ(1, app_icon_loader->fetch_count());
2483 model_observer_->clear_counts();
2485 // App panels should have a separate identifier than the app id
2486 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(app_id));
2488 // Setting the app image image should not change the panel if it set its icon
2489 app_panel_controller->set_image_set_by_controller(true);
2490 gfx::ImageSkia image;
2491 launcher_controller_->SetAppImage(app_id, image);
2492 EXPECT_EQ(0, model_observer_->changed());
2493 model_observer_->clear_counts();
2495 // Add a second app panel and verify that it get the same index as the first
2496 // one had, being added to the left of the existing panel.
2497 AppWindowLauncherItemController* app_panel_controller2 =
2498 new AppWindowLauncherItemController(
2499 LauncherItemController::TYPE_APP_PANEL,
2502 launcher_controller_.get());
2504 ash::ShelfID shelf_id2 = launcher_controller_->CreateAppLauncherItem(
2505 app_panel_controller2, app_id, ash::STATUS_RUNNING);
2506 EXPECT_EQ(panel_index, model_observer_->last_index());
2507 EXPECT_EQ(1, model_observer_->added());
2508 model_observer_->clear_counts();
2510 launcher_controller_->CloseLauncherItem(shelf_id2);
2511 launcher_controller_->CloseLauncherItem(shelf_id1);
2512 EXPECT_EQ(2, model_observer_->removed());
2515 // Tests that the Gmail extension matches more then the app itself claims with
2516 // the manifest file.
2517 TEST_F(ChromeLauncherControllerTest, GmailMatching) {
2518 InitLauncherControllerWithBrowser();
2520 // Create a Gmail browser tab.
2521 chrome::NewTab(browser());
2522 base::string16 title = ASCIIToUTF16("Test");
2523 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title);
2524 content::WebContents* content =
2525 browser()->tab_strip_model()->GetActiveWebContents();
2527 // Check that the launcher controller does not recognize the running app.
2528 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
2530 // Installing |extension3_| adds it to the launcher.
2531 ash::ShelfID gmail_id = model_->next_id();
2532 extension_service_->AddExtension(extension3_.get());
2533 EXPECT_EQ(3, model_->item_count());
2534 int gmail_index = model_->ItemIndexByID(gmail_id);
2535 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2536 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2538 // Check that it is now handled.
2539 EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
2541 // Check also that the app has detected that properly.
2542 ash::ShelfItem item_gmail;
2543 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2544 item_gmail.id = gmail_id;
2545 EXPECT_EQ(2U, launcher_controller_->GetApplicationList(item_gmail, 0).size());
2548 // Tests that the Gmail extension does not match the offline verison.
2549 TEST_F(ChromeLauncherControllerTest, GmailOfflineMatching) {
2550 InitLauncherControllerWithBrowser();
2552 // Create a Gmail browser tab.
2553 chrome::NewTab(browser());
2554 base::string16 title = ASCIIToUTF16("Test");
2555 NavigateAndCommitActiveTabWithTitle(browser(),
2556 GURL(offline_gmail_url),
2558 content::WebContents* content =
2559 browser()->tab_strip_model()->GetActiveWebContents();
2561 // Installing |extension3_| adds it to the launcher.
2562 ash::ShelfID gmail_id = model_->next_id();
2563 extension_service_->AddExtension(extension3_.get());
2564 EXPECT_EQ(3, model_->item_count());
2565 int gmail_index = model_->ItemIndexByID(gmail_id);
2566 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2567 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2569 // The content should not be able to be handled by the app.
2570 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
2573 // Verify that the launcher item positions are persisted and restored.
2574 TEST_F(ChromeLauncherControllerTest, PersistLauncherItemPositions) {
2575 InitLauncherController();
2577 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
2578 SetAppTabHelper(app_tab_helper);
2580 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2581 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
2583 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2584 EXPECT_EQ(0, tab_strip_model->count());
2585 chrome::NewTab(browser());
2586 chrome::NewTab(browser());
2587 EXPECT_EQ(2, tab_strip_model->count());
2588 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2589 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
2591 EXPECT_FALSE(launcher_controller_->IsAppPinned("1"));
2592 launcher_controller_->PinAppWithID("1");
2593 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
2594 launcher_controller_->PinAppWithID("2");
2596 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2597 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
2598 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
2599 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[3].type);
2601 // Move browser shortcut item from index 1 to index 3.
2603 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2604 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
2605 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
2606 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
2608 launcher_controller_.reset();
2609 if (!ash::Shell::HasInstance()) {
2610 delete item_delegate_manager_;
2612 // Clear already registered ShelfItemDelegate.
2613 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_);
2614 test.RemoveAllShelfItemDelegateForTest();
2616 model_.reset(new ash::ShelfModel);
2618 AddAppListLauncherItem();
2619 launcher_controller_.reset(
2620 ChromeLauncherController::CreateInstance(profile(), model_.get()));
2621 app_tab_helper = new TestAppTabHelperImpl;
2622 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2623 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
2624 SetAppTabHelper(app_tab_helper);
2625 if (!ash::Shell::HasInstance()) {
2626 item_delegate_manager_ = new ash::ShelfItemDelegateManager(model_.get());
2627 SetShelfItemDelegateManager(item_delegate_manager_);
2629 launcher_controller_->Init();
2631 // Check ShelfItems are restored after resetting ChromeLauncherController.
2632 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2633 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
2634 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
2635 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
2638 // Verifies pinned apps are persisted and restored.
2639 TEST_F(ChromeLauncherControllerTest, PersistPinned) {
2640 InitLauncherControllerWithBrowser();
2641 size_t initial_size = model_->items().size();
2643 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2644 EXPECT_EQ(1, tab_strip_model->count());
2646 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
2647 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2648 SetAppTabHelper(app_tab_helper);
2650 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl;
2651 SetAppIconLoader(app_icon_loader);
2652 EXPECT_EQ(0, app_icon_loader->fetch_count());
2654 launcher_controller_->PinAppWithID("1");
2655 ash::ShelfID id = launcher_controller_->GetShelfIDForAppID("1");
2656 int app_index = model_->ItemIndexByID(id);
2657 EXPECT_EQ(1, app_icon_loader->fetch_count());
2658 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type);
2659 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
2660 EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
2661 EXPECT_EQ(initial_size + 1, model_->items().size());
2663 launcher_controller_.reset();
2664 if (!ash::Shell::HasInstance()) {
2665 delete item_delegate_manager_;
2667 // Clear already registered ShelfItemDelegate.
2668 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_);
2669 test.RemoveAllShelfItemDelegateForTest();
2671 model_.reset(new ash::ShelfModel);
2673 AddAppListLauncherItem();
2674 launcher_controller_.reset(
2675 ChromeLauncherController::CreateInstance(profile(), model_.get()));
2676 app_tab_helper = new TestAppTabHelperImpl;
2677 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2678 SetAppTabHelper(app_tab_helper);
2679 app_icon_loader = new TestAppIconLoaderImpl;
2680 SetAppIconLoader(app_icon_loader);
2681 if (!ash::Shell::HasInstance()) {
2682 item_delegate_manager_ = new ash::ShelfItemDelegateManager(model_.get());
2683 SetShelfItemDelegateManager(item_delegate_manager_);
2685 launcher_controller_->Init();
2687 EXPECT_EQ(1, app_icon_loader->fetch_count());
2688 ASSERT_EQ(initial_size + 1, model_->items().size());
2689 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
2690 EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
2691 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type);
2693 launcher_controller_->UnpinAppWithID("1");
2694 ASSERT_EQ(initial_size, model_->items().size());