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 "apps/app_window_contents.h"
51 #include "apps/app_window_registry.h"
52 #include "apps/ui/native_app_window.h"
53 #include "ash/test/test_session_state_delegate.h"
54 #include "ash/test/test_shell_delegate.h"
55 #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
56 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
57 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
58 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
59 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
60 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
61 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
62 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
63 #include "chrome/common/chrome_constants.h"
64 #include "chrome/common/chrome_switches.h"
65 #include "chrome/test/base/testing_browser_process.h"
66 #include "chrome/test/base/testing_profile_manager.h"
67 #include "content/public/browser/web_contents_observer.h"
68 #include "content/public/test/test_utils.h"
69 #include "ui/aura/window.h"
72 using base::ASCIIToUTF16;
73 using extensions::Extension;
74 using extensions::Manifest;
75 using extensions::UnloadedExtensionInfo;
78 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
79 const char* gmail_url = "https://mail.google.com/mail/u";
80 const char* kGmailLaunchURL = "https://mail.google.com/mail/ca";
82 #if defined(OS_CHROMEOS)
83 // As defined in /chromeos/dbus/cryptohome_client.cc.
84 const char kUserIdHashSuffix[] = "-hash";
86 // An extension prefix.
87 const char kCrxAppPrefix[] = "_crx_";
90 // ShelfModelObserver implementation that tracks what messages are invoked.
91 class TestShelfModelObserver : public ash::ShelfModelObserver {
93 TestShelfModelObserver()
99 virtual ~TestShelfModelObserver() {
102 // Overridden from ash::ShelfModelObserver:
103 virtual void ShelfItemAdded(int index) OVERRIDE {
108 virtual void ShelfItemRemoved(int index, ash::ShelfID id) OVERRIDE {
113 virtual void ShelfItemChanged(int index,
114 const ash::ShelfItem& old_item) OVERRIDE {
119 virtual void ShelfItemMoved(int start_index, int target_index) OVERRIDE {
120 last_index_ = target_index;
123 virtual void ShelfStatusChanged() OVERRIDE {
126 void clear_counts() {
133 int added() const { return added_; }
134 int removed() const { return removed_; }
135 int changed() const { return changed_; }
136 int last_index() const { return last_index_; }
144 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver);
147 // Test implementation of AppIconLoader.
148 class TestAppIconLoaderImpl : public extensions::AppIconLoader {
150 TestAppIconLoaderImpl() : fetch_count_(0) {
153 virtual ~TestAppIconLoaderImpl() {
156 // AppIconLoader implementation:
157 virtual void FetchImage(const std::string& id) OVERRIDE {
161 virtual void ClearImage(const std::string& id) OVERRIDE {
164 virtual void UpdateImage(const std::string& id) OVERRIDE {
167 int fetch_count() const { return fetch_count_; }
172 DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl);
175 // Test implementation of AppTabHelper.
176 class TestAppTabHelperImpl : public ChromeLauncherController::AppTabHelper {
178 TestAppTabHelperImpl() {}
179 virtual ~TestAppTabHelperImpl() {}
181 // Sets the id for the specified tab. The id is removed if Remove() is
183 void SetAppID(content::WebContents* tab, const std::string& id) {
184 tab_id_map_[tab] = id;
187 // Returns true if there is an id registered for |tab|.
188 bool HasAppID(content::WebContents* tab) const {
189 return tab_id_map_.find(tab) != tab_id_map_.end();
192 // AppTabHelper implementation:
193 virtual std::string GetAppID(content::WebContents* tab) OVERRIDE {
194 return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] :
198 virtual bool IsValidIDForCurrentUser(const std::string& id) OVERRIDE {
199 for (TabToStringMap::const_iterator i = tab_id_map_.begin();
200 i != tab_id_map_.end(); ++i) {
207 virtual void SetCurrentUser(Profile* profile) OVERRIDE {
208 // We can ignore this for now.
212 typedef std::map<content::WebContents*, std::string> TabToStringMap;
214 TabToStringMap tab_id_map_;
216 DISALLOW_COPY_AND_ASSIGN(TestAppTabHelperImpl);
219 // Test implementation of a V2 app launcher item controller.
220 class TestV2AppLauncherItemController : public LauncherItemController {
222 TestV2AppLauncherItemController(const std::string& app_id,
223 ChromeLauncherController* controller)
224 : LauncherItemController(LauncherItemController::TYPE_APP,
229 virtual ~TestV2AppLauncherItemController() {}
231 // Override for LauncherItemController:
232 virtual bool IsOpen() const OVERRIDE { return true; }
233 virtual bool IsVisible() const OVERRIDE { return true; }
234 virtual void Launch(ash::LaunchSource source, int event_flags) OVERRIDE {}
235 virtual bool Activate(ash::LaunchSource source) OVERRIDE { return false; }
236 virtual void Close() OVERRIDE {}
237 virtual bool ItemSelected(const ui::Event& event) OVERRIDE { return false; }
238 virtual base::string16 GetTitle() OVERRIDE { return base::string16(); }
239 virtual ChromeLauncherAppMenuItems GetApplicationList(
240 int event_flags) OVERRIDE {
241 ChromeLauncherAppMenuItems items;
243 new ChromeLauncherAppMenuItem(base::string16(), NULL, false));
245 new ChromeLauncherAppMenuItem(base::string16(), NULL, false));
248 virtual ui::MenuModel* CreateContextMenu(aura::Window* root_window) OVERRIDE {
251 virtual ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) OVERRIDE {
254 virtual bool IsDraggable() OVERRIDE { return false; }
255 virtual bool ShouldShowTooltip() OVERRIDE { return false; }
258 DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController);
263 class ChromeLauncherControllerTest : public BrowserWithTestWindowTest {
265 ChromeLauncherControllerTest()
266 : BrowserWithTestWindowTest(
267 Browser::TYPE_TABBED,
268 chrome::HOST_DESKTOP_TYPE_ASH,
270 test_controller_(NULL),
271 extension_service_(NULL) {
274 virtual ~ChromeLauncherControllerTest() {
277 virtual void SetUp() OVERRIDE {
278 BrowserWithTestWindowTest::SetUp();
280 model_.reset(new ash::ShelfModel);
281 model_observer_.reset(new TestShelfModelObserver);
282 model_->AddObserver(model_observer_.get());
284 if (ash::Shell::HasInstance()) {
285 item_delegate_manager_ =
286 ash::Shell::GetInstance()->shelf_item_delegate_manager();
288 item_delegate_manager_ =
289 new ash::ShelfItemDelegateManager(model_.get());
292 base::DictionaryValue manifest;
293 manifest.SetString(extensions::manifest_keys::kName,
294 "launcher controller test extension");
295 manifest.SetString(extensions::manifest_keys::kVersion, "1");
296 manifest.SetString(extensions::manifest_keys::kDescription,
297 "for testing pinned apps");
299 extensions::TestExtensionSystem* extension_system(
300 static_cast<extensions::TestExtensionSystem*>(
301 extensions::ExtensionSystem::Get(profile())));
302 extension_service_ = extension_system->CreateExtensionService(
303 CommandLine::ForCurrentProcess(), base::FilePath(), false);
306 extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
309 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
311 extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
314 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
316 // Fake gmail extension.
317 base::DictionaryValue manifest_gmail;
318 manifest_gmail.SetString(extensions::manifest_keys::kName,
319 "Gmail launcher controller test extension");
320 manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1");
321 manifest_gmail.SetString(extensions::manifest_keys::kDescription,
322 "for testing pinned Gmail");
323 manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL,
325 base::ListValue* list = new base::ListValue();
326 list->Append(new base::StringValue("*://mail.google.com/mail/ca"));
327 manifest_gmail.Set(extensions::manifest_keys::kWebURLs, list);
329 extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
332 extension_misc::kGmailAppId,
335 // Fake search extension.
336 extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
339 extension_misc::kGoogleSearchAppId,
341 extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
344 "cccccccccccccccccccccccccccccccc",
346 extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
349 "dddddddddddddddddddddddddddddddd",
351 extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
354 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
356 extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
359 "ffffffffffffffffffffffffffffffff",
363 // Creates a running V2 app (not pinned) of type |app_id|.
364 virtual void CreateRunningV2App(const std::string& app_id) {
365 DCHECK(!test_controller_);
367 launcher_controller_->CreateAppShortcutLauncherItemWithType(
369 model_->item_count(),
370 ash::TYPE_PLATFORM_APP);
372 // Change the created launcher controller into a V2 app controller.
373 test_controller_ = new TestV2AppLauncherItemController(app_id,
374 launcher_controller_.get());
375 launcher_controller_->SetItemController(id, test_controller_);
378 // Sets the stage for a multi user test.
379 virtual void SetUpMultiUserScenario(base::ListValue* user_a,
380 base::ListValue* user_b) {
381 InitLauncherController();
382 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
384 // Set an empty pinned pref to begin with.
385 base::ListValue no_user;
386 SetShelfChromeIconIndex(0);
387 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
389 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
391 // Assume all applications have been added already.
392 extension_service_->AddExtension(extension1_.get());
393 extension_service_->AddExtension(extension2_.get());
394 extension_service_->AddExtension(extension3_.get());
395 extension_service_->AddExtension(extension4_.get());
396 extension_service_->AddExtension(extension5_.get());
397 extension_service_->AddExtension(extension6_.get());
398 extension_service_->AddExtension(extension7_.get());
399 extension_service_->AddExtension(extension8_.get());
400 // There should be nothing in the list by now.
401 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
403 // Set user a preferences.
404 InsertPrefValue(user_a, 0, extension1_->id());
405 InsertPrefValue(user_a, 1, extension2_->id());
406 InsertPrefValue(user_a, 2, extension3_->id());
407 InsertPrefValue(user_a, 3, extension4_->id());
408 InsertPrefValue(user_a, 4, extension5_->id());
409 InsertPrefValue(user_a, 5, extension6_->id());
411 // Set user b preferences.
412 InsertPrefValue(user_b, 0, extension7_->id());
413 InsertPrefValue(user_b, 1, extension8_->id());
416 virtual void TearDown() OVERRIDE {
417 if (!ash::Shell::HasInstance())
418 delete item_delegate_manager_;
419 model_->RemoveObserver(model_observer_.get());
420 model_observer_.reset();
421 launcher_controller_.reset();
424 BrowserWithTestWindowTest::TearDown();
427 void AddAppListLauncherItem() {
428 ash::ShelfItem app_list;
429 app_list.type = ash::TYPE_APP_LIST;
430 model_->Add(app_list);
433 void InitLauncherController() {
434 AddAppListLauncherItem();
435 launcher_controller_.reset(
436 new ChromeLauncherController(profile(), model_.get()));
437 if (!ash::Shell::HasInstance())
438 SetShelfItemDelegateManager(item_delegate_manager_);
439 launcher_controller_->Init();
442 void InitLauncherControllerWithBrowser() {
443 chrome::NewTab(browser());
444 BrowserList::SetLastActive(browser());
445 InitLauncherController();
448 void SetAppIconLoader(extensions::AppIconLoader* loader) {
449 launcher_controller_->SetAppIconLoaderForTest(loader);
452 void SetAppTabHelper(ChromeLauncherController::AppTabHelper* helper) {
453 launcher_controller_->SetAppTabHelperForTest(helper);
456 void SetShelfItemDelegateManager(ash::ShelfItemDelegateManager* manager) {
457 launcher_controller_->SetShelfItemDelegateManagerForTest(manager);
460 void InsertPrefValue(base::ListValue* pref_value,
462 const std::string& extension_id) {
463 base::DictionaryValue* entry = new base::DictionaryValue();
464 entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id);
465 pref_value->Insert(index, entry);
468 // Gets the currently configured app launchers from the controller.
469 void GetAppLaunchers(ChromeLauncherController* controller,
470 std::vector<std::string>* launchers) {
472 for (ash::ShelfItems::const_iterator iter(model_->items().begin());
473 iter != model_->items().end(); ++iter) {
474 ChromeLauncherController::IDToItemControllerMap::const_iterator
475 entry(controller->id_to_item_controller_map_.find(iter->id));
476 if (iter->type == ash::TYPE_APP_SHORTCUT &&
477 entry != controller->id_to_item_controller_map_.end()) {
478 launchers->push_back(entry->second->app_id());
483 // Get the setup of the currently shown launcher items in one string.
484 // Each pinned element will start with a big letter, each running but not
485 // pinned V1 app will start with a small letter and each running but not
486 // pinned V2 app will start with a '*' + small letter.
487 std::string GetPinnedAppStatus() {
489 for (int i = 0; i < model_->item_count(); i++) {
492 switch (model_->items()[i].type) {
493 case ash::TYPE_PLATFORM_APP:
496 case ash::TYPE_WINDOWED_APP: {
497 const std::string& app =
498 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id);
499 if (app == extension1_->id()) {
502 launcher_controller_->IsAppPinned(extension1_->id()));
503 } else if (app == extension2_->id()) {
506 launcher_controller_->IsAppPinned(extension2_->id()));
507 } else if (app == extension3_->id()) {
510 launcher_controller_->IsAppPinned(extension3_->id()));
511 } else if (app == extension4_->id()) {
514 launcher_controller_->IsAppPinned(extension4_->id()));
515 } else if (app == extension5_->id()) {
518 launcher_controller_->IsAppPinned(extension5_->id()));
519 } else if (app == extension6_->id()) {
522 launcher_controller_->IsAppPinned(extension6_->id()));
523 } else if (app == extension7_->id()) {
526 launcher_controller_->IsAppPinned(extension7_->id()));
527 } else if (app == extension8_->id()) {
530 launcher_controller_->IsAppPinned(extension8_->id()));
536 case ash::TYPE_APP_SHORTCUT: {
537 const std::string& app =
538 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id);
539 if (app == extension1_->id()) {
541 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
542 } else if (app == extension2_->id()) {
544 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
545 } else if (app == extension3_->id()) {
547 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
548 } else if (app == extension4_->id()) {
550 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
551 } else if (app == extension5_->id()) {
553 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension5_->id()));
554 } else if (app == extension6_->id()) {
556 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension6_->id()));
557 } else if (app == extension7_->id()) {
559 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension7_->id()));
560 } else if (app == extension8_->id()) {
562 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension8_->id()));
568 case ash::TYPE_BROWSER_SHORTCUT:
571 case ash::TYPE_APP_LIST:
582 // Set the index at which the chrome icon should be.
583 void SetShelfChromeIconIndex(int index) {
584 profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
588 // Remember the order of unpinned but running applications for the current
590 void RememberUnpinnedRunningApplicationOrder() {
591 launcher_controller_->RememberUnpinnedRunningApplicationOrder();
594 // Restore the order of running but unpinned applications for a given user.
595 void RestoreUnpinnedRunningApplicationOrder(const std::string& user_id) {
596 launcher_controller_->RestoreUnpinnedRunningApplicationOrder(user_id);
599 // Needed for extension service & friends to work.
600 scoped_refptr<Extension> extension1_;
601 scoped_refptr<Extension> extension2_;
602 scoped_refptr<Extension> extension3_;
603 scoped_refptr<Extension> extension4_;
604 scoped_refptr<Extension> extension5_;
605 scoped_refptr<Extension> extension6_;
606 scoped_refptr<Extension> extension7_;
607 scoped_refptr<Extension> extension8_;
608 scoped_ptr<ChromeLauncherController> launcher_controller_;
609 scoped_ptr<TestShelfModelObserver> model_observer_;
610 scoped_ptr<ash::ShelfModel> model_;
612 // |item_delegate_manager_| owns |test_controller_|.
613 LauncherItemController* test_controller_;
615 ExtensionService* extension_service_;
617 ash::ShelfItemDelegateManager* item_delegate_manager_;
620 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerTest);
623 #if defined(OS_CHROMEOS)
624 // A browser window proxy which is able to associate an aura native window with
626 class TestBrowserWindowAura : public TestBrowserWindow {
628 // |native_window| will still be owned by the caller after the constructor
630 explicit TestBrowserWindowAura(aura::Window* native_window)
631 : native_window_(native_window) {
633 virtual ~TestBrowserWindowAura() {}
635 virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
636 return native_window_.get();
639 Browser* browser() { return browser_.get(); }
641 void CreateBrowser(const Browser::CreateParams& params) {
642 Browser::CreateParams create_params = params;
643 create_params.window = this;
644 browser_.reset(new Browser(create_params));
648 scoped_ptr<Browser> browser_;
649 scoped_ptr<aura::Window> native_window_;
651 DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura);
654 // Creates a test browser window which has a native window.
655 scoped_ptr<TestBrowserWindowAura> CreateTestBrowserWindow(
656 const Browser::CreateParams& params) {
658 aura::Window* window = new aura::Window(NULL);
660 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
661 window->Init(aura::WINDOW_LAYER_TEXTURED);
664 scoped_ptr<TestBrowserWindowAura> browser_window(
665 new TestBrowserWindowAura(window));
666 browser_window->CreateBrowser(params);
667 return browser_window.Pass();
670 // Watches WebContents and blocks until it is destroyed. This is needed for
671 // the destruction of a V2 application.
672 class WebContentsDestroyedWatcher : public content::WebContentsObserver {
674 explicit WebContentsDestroyedWatcher(content::WebContents* web_contents)
675 : content::WebContentsObserver(web_contents),
676 message_loop_runner_(new content::MessageLoopRunner) {
677 EXPECT_TRUE(web_contents != NULL);
679 virtual ~WebContentsDestroyedWatcher() {}
681 // Waits until the WebContents is destroyed.
683 message_loop_runner_->Run();
687 // Overridden WebContentsObserver methods.
688 virtual void WebContentsDestroyed() OVERRIDE {
689 message_loop_runner_->Quit();
692 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
694 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedWatcher);
697 // A V1 windowed application.
698 class V1App : public TestBrowserWindow {
700 V1App(Profile* profile, const std::string& app_name) {
702 native_window_.reset(new aura::Window(NULL));
703 native_window_->set_id(0);
704 native_window_->SetType(ui::wm::WINDOW_TYPE_POPUP);
705 native_window_->Init(aura::WINDOW_LAYER_TEXTURED);
706 native_window_->Show();
707 aura::client::ParentWindowWithContext(native_window_.get(),
708 ash::Shell::GetPrimaryRootWindow(),
709 gfx::Rect(10, 10, 20, 30));
710 Browser::CreateParams params =
711 Browser::CreateParams::CreateForApp(kCrxAppPrefix + app_name,
712 true /* trusted_source */,
715 chrome::HOST_DESKTOP_TYPE_ASH);
716 params.window = this;
717 browser_.reset(new Browser(params));
718 chrome::AddTabAt(browser_.get(), GURL(), 0, true);
722 // close all tabs. Note that we do not need to destroy the browser itself.
723 browser_->tab_strip_model()->CloseAllTabs();
726 Browser* browser() { return browser_.get(); }
728 // TestBrowserWindow override:
729 virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
730 return native_window_.get();
734 // The associated browser with this app.
735 scoped_ptr<Browser> browser_;
737 // The native window we use.
738 scoped_ptr<aura::Window> native_window_;
740 DISALLOW_COPY_AND_ASSIGN(V1App);
743 // A V2 application which gets created with an |extension| and for a |profile|.
744 // Upon destruction it will properly close the application.
747 V2App(Profile* profile, const extensions::Extension* extension) {
748 window_ = new apps::AppWindow(profile, new ChromeAppDelegate(), extension);
749 apps::AppWindow::CreateParams params = apps::AppWindow::CreateParams();
751 GURL(std::string()), new apps::AppWindowContentsImpl(window_), params);
755 WebContentsDestroyedWatcher destroyed_watcher(window_->web_contents());
756 window_->GetBaseWindow()->Close();
757 destroyed_watcher.Wait();
760 apps::AppWindow* window() { return window_; }
763 // The app window which represents the application. Note that the window
764 // deletes itself asynchronously after window_->GetBaseWindow()->Close() gets
766 apps::AppWindow* window_;
768 DISALLOW_COPY_AND_ASSIGN(V2App);
771 // The testing framework to test multi profile scenarios.
772 class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest
773 : public ChromeLauncherControllerTest {
775 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() {
778 virtual ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() {
781 // Overwrite the Setup function to enable multi profile and needed objects.
782 virtual void SetUp() OVERRIDE {
783 profile_manager_.reset(
784 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
786 ASSERT_TRUE(profile_manager_->SetUp());
788 // AvatarMenu and multiple profiles works after user logged in.
789 profile_manager_->SetLoggedIn(true);
791 // Initialize the UserManager singleton to a fresh FakeUserManager instance.
792 user_manager_enabler_.reset(
793 new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
795 // Initialize the rest.
796 ChromeLauncherControllerTest::SetUp();
798 // Get some base objects.
799 session_delegate()->set_logged_in_users(2);
800 shell_delegate_ = static_cast<ash::test::TestShellDelegate*>(
801 ash::Shell::GetInstance()->delegate());
802 shell_delegate_->set_multi_profiles_enabled(true);
805 virtual void TearDown() {
806 ChromeLauncherControllerTest::TearDown();
807 user_manager_enabler_.reset();
808 for (ProfileToNameMap::iterator it = created_profiles_.begin();
809 it != created_profiles_.end(); ++it)
810 profile_manager_->DeleteTestingProfile(it->second);
812 // A Task is leaked if we don't destroy everything, then run the message
814 base::MessageLoop::current()->PostTask(FROM_HERE,
815 base::MessageLoop::QuitClosure());
816 base::MessageLoop::current()->Run();
819 // Creates a profile for a given |user_name|. Note that this class will keep
820 // the ownership of the created object.
821 TestingProfile* CreateMultiUserProfile(const std::string& user_name) {
822 std::string email_string = user_name + "@example.com";
823 static_cast<ash::test::TestSessionStateDelegate*>(
824 ash::Shell::GetInstance()->session_state_delegate())
825 ->AddUser(email_string);
826 // Add a user to the fake user manager.
827 session_delegate()->AddUser(email_string);
828 GetFakeUserManager()->AddUser(email_string);
830 GetFakeUserManager()->UserLoggedIn(
832 email_string + kUserIdHashSuffix,
835 std::string profile_name =
836 chrome::kProfileDirPrefix + email_string + kUserIdHashSuffix;
837 TestingProfile* profile = profile_manager()->CreateTestingProfile(
839 scoped_ptr<PrefServiceSyncable>(),
840 ASCIIToUTF16(email_string), 0, std::string(),
841 TestingProfile::TestingFactories());
842 profile->set_profile_name(email_string);
843 EXPECT_TRUE(profile);
844 // Remember the profile name so that we can destroy it upon destruction.
845 created_profiles_[profile] = profile_name;
846 if (chrome::MultiUserWindowManager::GetInstance())
847 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
848 if (launcher_controller_)
849 launcher_controller_->AdditionalUserAddedToSession(profile);
853 // Switch to another user.
854 void SwitchActiveUser(const std::string& name) {
855 session_delegate()->SwitchActiveUser(name);
856 GetFakeUserManager()->SwitchActiveUser(name);
857 chrome::MultiUserWindowManagerChromeOS* manager =
858 static_cast<chrome::MultiUserWindowManagerChromeOS*>(
859 chrome::MultiUserWindowManager::GetInstance());
860 manager->SetAnimationSpeedForTest(
861 chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
862 manager->ActiveUserChanged(name);
863 launcher_controller_->browser_status_monitor_for_test()->
864 ActiveUserChanged(name);
865 launcher_controller_->app_window_controller_for_test()->
866 ActiveUserChanged(name);
869 // Creates a browser with a |profile| and load a tab with a |title| and |url|.
870 Browser* CreateBrowserAndTabWithProfile(Profile* profile,
871 const std::string& title,
872 const std::string& url) {
873 Browser::CreateParams params(profile, chrome::HOST_DESKTOP_TYPE_ASH);
874 Browser* browser = chrome::CreateBrowserWithTestWindowForParams(¶ms);
875 chrome::NewTab(browser);
877 BrowserList::SetLastActive(browser);
878 NavigateAndCommitActiveTabWithTitle(
879 browser, GURL(url), ASCIIToUTF16(title));
883 // Creates a running V1 application.
884 // Note that with the use of the app_tab_helper as done below, this is only
885 // usable with a single v1 application.
886 V1App* CreateRunningV1App(Profile* profile,
887 const std::string& app_name,
888 const std::string& url) {
889 V1App* v1_app = new V1App(profile, app_name);
890 // Create a new app tab helper and assign it to the launcher so that this
891 // app gets properly detected.
892 // TODO(skuhne): Create a more intelligent app tab helper which is able to
893 // detect all running apps properly.
894 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
895 app_tab_helper->SetAppID(
896 v1_app->browser()->tab_strip_model()->GetWebContentsAt(0),
898 SetAppTabHelper(app_tab_helper);
900 NavigateAndCommitActiveTabWithTitle(
901 v1_app->browser(), GURL(url), ASCIIToUTF16(""));
905 ash::test::TestSessionStateDelegate* session_delegate() {
906 return static_cast<ash::test::TestSessionStateDelegate*>(
907 ash::Shell::GetInstance()->session_state_delegate());
909 ash::test::TestShellDelegate* shell_delegate() { return shell_delegate_; }
911 // Override BrowserWithTestWindowTest:
912 virtual TestingProfile* CreateProfile() OVERRIDE {
913 return CreateMultiUserProfile("user1");
915 virtual void DestroyProfile(TestingProfile* profile) OVERRIDE {
916 // Delete the profile through our profile manager.
917 ProfileToNameMap::iterator it = created_profiles_.find(profile);
918 DCHECK(it != created_profiles_.end());
919 profile_manager_->DeleteTestingProfile(it->second);
920 created_profiles_.erase(it);
924 typedef std::map<Profile*, std::string> ProfileToNameMap;
925 TestingProfileManager* profile_manager() { return profile_manager_.get(); }
927 chromeos::FakeUserManager* GetFakeUserManager() {
928 return static_cast<chromeos::FakeUserManager*>(
929 user_manager::UserManager::Get());
932 scoped_ptr<TestingProfileManager> profile_manager_;
933 scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
935 ash::test::TestShellDelegate* shell_delegate_;
937 ProfileToNameMap created_profiles_;
939 DISALLOW_COPY_AND_ASSIGN(
940 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest);
942 #endif // defined(OS_CHROMEOS)
945 TEST_F(ChromeLauncherControllerTest, DefaultApps) {
946 InitLauncherController();
947 // Model should only contain the browser shortcut and app list items.
948 EXPECT_EQ(2, model_->item_count());
949 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
950 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
951 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
953 // Installing |extension3_| should add it to the launcher - behind the
955 extension_service_->AddExtension(extension3_.get());
956 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
957 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
958 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
961 // Check that the restauration of launcher items is happening in the same order
962 // as the user has pinned them (on another system) when they are synced reverse
964 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsReverseOrder) {
965 InitLauncherController();
967 base::ListValue policy_value;
968 InsertPrefValue(&policy_value, 0, extension1_->id());
969 InsertPrefValue(&policy_value, 1, extension2_->id());
970 InsertPrefValue(&policy_value, 2, extension3_->id());
971 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
972 policy_value.DeepCopy());
973 SetShelfChromeIconIndex(0);
974 // Model should only contain the browser shortcut and app list items.
975 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
976 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
977 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
978 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
980 // Installing |extension3_| should add it to the shelf - behind the
983 extension_service_->AddExtension(extension3_.get());
984 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
985 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
986 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
988 // Installing |extension2_| should add it to the launcher - behind the
989 // chrome icon, but in first location.
990 extension_service_->AddExtension(extension2_.get());
991 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
992 EXPECT_EQ("AppList, Chrome, App2, App3", GetPinnedAppStatus());
994 // Installing |extension1_| should add it to the launcher - behind the
995 // chrome icon, but in first location.
996 extension_service_->AddExtension(extension1_.get());
997 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1000 // Check that the restauration of launcher items is happening in the same order
1001 // as the user has pinned them (on another system) when they are synced random
1003 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrder) {
1004 InitLauncherController();
1006 base::ListValue policy_value;
1007 InsertPrefValue(&policy_value, 0, extension1_->id());
1008 InsertPrefValue(&policy_value, 1, extension2_->id());
1009 InsertPrefValue(&policy_value, 2, extension3_->id());
1010 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1011 policy_value.DeepCopy());
1012 SetShelfChromeIconIndex(0);
1013 // Model should only contain the browser shortcut and app list items.
1014 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1015 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1016 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1017 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1019 // Installing |extension2_| should add it to the launcher - behind the
1021 extension_service_->AddExtension(extension2_.get());
1022 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1023 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1024 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1026 // Installing |extension1_| should add it to the launcher - behind the
1027 // chrome icon, but in first location.
1028 extension_service_->AddExtension(extension1_.get());
1029 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1030 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
1032 // Installing |extension3_| should add it to the launcher - behind the
1033 // chrome icon, but in first location.
1034 extension_service_->AddExtension(extension3_.get());
1035 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1038 // Check that the restauration of launcher items is happening in the same order
1039 // as the user has pinned / moved them (on another system) when they are synced
1040 // random order - including the chrome icon.
1041 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrderChromeMoved) {
1042 InitLauncherController();
1044 base::ListValue policy_value;
1045 InsertPrefValue(&policy_value, 0, extension1_->id());
1046 InsertPrefValue(&policy_value, 1, extension2_->id());
1047 InsertPrefValue(&policy_value, 2, extension3_->id());
1048 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1049 policy_value.DeepCopy());
1050 SetShelfChromeIconIndex(1);
1051 // Model should only contain the browser shortcut and app list items.
1052 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1053 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1054 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1055 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1057 // Installing |extension2_| should add it to the shelf - behind the
1059 ash::ShelfItem item;
1060 extension_service_->AddExtension(extension2_.get());
1061 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1062 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1063 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1065 // Installing |extension1_| should add it to the launcher - behind the
1066 // chrome icon, but in first location.
1067 extension_service_->AddExtension(extension1_.get());
1068 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1069 EXPECT_EQ("AppList, App1, Chrome, App2", GetPinnedAppStatus());
1071 // Installing |extension3_| should add it to the launcher - behind the
1072 // chrome icon, but in first location.
1073 extension_service_->AddExtension(extension3_.get());
1074 EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus());
1077 // Check that syncing to a different state does the correct thing.
1078 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsResyncOrder) {
1079 InitLauncherController();
1080 base::ListValue policy_value;
1081 InsertPrefValue(&policy_value, 0, extension1_->id());
1082 InsertPrefValue(&policy_value, 1, extension2_->id());
1083 InsertPrefValue(&policy_value, 2, extension3_->id());
1084 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1085 policy_value.DeepCopy());
1086 // The shelf layout has always one static item at the beginning (App List).
1087 SetShelfChromeIconIndex(0);
1088 extension_service_->AddExtension(extension2_.get());
1089 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus());
1090 extension_service_->AddExtension(extension1_.get());
1091 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus());
1092 extension_service_->AddExtension(extension3_.get());
1093 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus());
1095 // Change the order with increasing chrome position and decreasing position.
1096 base::ListValue policy_value1;
1097 InsertPrefValue(&policy_value1, 0, extension3_->id());
1098 InsertPrefValue(&policy_value1, 1, extension1_->id());
1099 InsertPrefValue(&policy_value1, 2, extension2_->id());
1100 SetShelfChromeIconIndex(3);
1101 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1102 policy_value1.DeepCopy());
1103 EXPECT_EQ("AppList, App3, App1, App2, Chrome", GetPinnedAppStatus());
1104 base::ListValue policy_value2;
1105 InsertPrefValue(&policy_value2, 0, extension2_->id());
1106 InsertPrefValue(&policy_value2, 1, extension3_->id());
1107 InsertPrefValue(&policy_value2, 2, extension1_->id());
1108 SetShelfChromeIconIndex(2);
1109 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1110 policy_value2.DeepCopy());
1111 EXPECT_EQ("AppList, App2, App3, Chrome, App1", GetPinnedAppStatus());
1113 // Check that the chrome icon can also be at the first possible location.
1114 SetShelfChromeIconIndex(0);
1115 base::ListValue policy_value3;
1116 InsertPrefValue(&policy_value3, 0, extension3_->id());
1117 InsertPrefValue(&policy_value3, 1, extension2_->id());
1118 InsertPrefValue(&policy_value3, 2, extension1_->id());
1119 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1120 policy_value3.DeepCopy());
1121 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1123 // Check that unloading of extensions works as expected.
1124 extension_service_->UnloadExtension(extension1_->id(),
1125 UnloadedExtensionInfo::REASON_UNINSTALL);
1126 EXPECT_EQ("AppList, Chrome, App3, App2", GetPinnedAppStatus());
1128 extension_service_->UnloadExtension(extension2_->id(),
1129 UnloadedExtensionInfo::REASON_UNINSTALL);
1130 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1132 // Check that an update of an extension does not crash the system.
1133 extension_service_->UnloadExtension(extension3_->id(),
1134 UnloadedExtensionInfo::REASON_UPDATE);
1135 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus());
1138 // Check that simple locking of an application will 'create' a launcher item.
1139 TEST_F(ChromeLauncherControllerTest, CheckLockApps) {
1140 InitLauncherController();
1141 // Model should only contain the browser shortcut and app list items.
1142 EXPECT_EQ(2, model_->item_count());
1143 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1145 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1146 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1148 launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
1150 launcher_controller_->LockV1AppWithID(extension1_->id());
1152 EXPECT_EQ(3, model_->item_count());
1153 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1154 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1155 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1156 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1158 launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
1160 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1162 EXPECT_EQ(2, model_->item_count());
1163 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1165 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1166 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1168 launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
1171 // Check that multiple locks of an application will be properly handled.
1172 TEST_F(ChromeLauncherControllerTest, CheckMultiLockApps) {
1173 InitLauncherController();
1174 // Model should only contain the browser shortcut and app list items.
1175 EXPECT_EQ(2, model_->item_count());
1176 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1178 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1180 for (int i = 0; i < 2; i++) {
1181 launcher_controller_->LockV1AppWithID(extension1_->id());
1183 EXPECT_EQ(3, model_->item_count());
1184 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1185 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1186 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(
1187 extension1_->id()));
1190 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1192 EXPECT_EQ(3, model_->item_count());
1193 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1194 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1195 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1197 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1199 EXPECT_EQ(2, model_->item_count());
1200 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1202 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1203 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1205 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1208 // Check that already pinned items are not effected by locks.
1209 TEST_F(ChromeLauncherControllerTest, CheckAlreadyPinnedLockApps) {
1210 InitLauncherController();
1211 // Model should only contain the browser shortcut and app list items.
1212 EXPECT_EQ(2, model_->item_count());
1213 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1215 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1217 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1218 launcher_controller_->PinAppWithID(extension1_->id());
1219 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1221 EXPECT_EQ(3, model_->item_count());
1222 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1223 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1225 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1227 launcher_controller_->LockV1AppWithID(extension1_->id());
1229 EXPECT_EQ(3, model_->item_count());
1230 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1231 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1233 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1235 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1237 EXPECT_EQ(3, model_->item_count());
1238 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1239 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1241 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1243 launcher_controller_->UnpinAppWithID(extension1_->id());
1245 EXPECT_EQ(2, model_->item_count());
1248 // Check that already pinned items which get locked stay after unpinning.
1249 TEST_F(ChromeLauncherControllerTest, CheckPinnedAppsStayAfterUnlock) {
1250 InitLauncherController();
1251 // Model should only contain the browser shortcut and app list items.
1252 EXPECT_EQ(2, model_->item_count());
1253 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1255 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1257 launcher_controller_->PinAppWithID(extension1_->id());
1259 EXPECT_EQ(3, model_->item_count());
1260 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1261 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1263 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1265 launcher_controller_->LockV1AppWithID(extension1_->id());
1267 EXPECT_EQ(3, model_->item_count());
1268 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1269 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1271 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1273 launcher_controller_->UnpinAppWithID(extension1_->id());
1275 EXPECT_EQ(3, model_->item_count());
1276 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1277 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1278 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1280 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1282 EXPECT_EQ(2, model_->item_count());
1285 #if defined(OS_CHROMEOS)
1286 // Check that running applications wich are not pinned get properly restored
1287 // upon user change.
1288 TEST_F(ChromeLauncherControllerTest, CheckRunningAppOrder) {
1289 InitLauncherController();
1290 // Model should only contain the browser shortcut and app list items.
1291 EXPECT_EQ(2, model_->item_count());
1293 // Add a few running applications.
1294 launcher_controller_->LockV1AppWithID(extension1_->id());
1295 launcher_controller_->LockV1AppWithID(extension2_->id());
1296 launcher_controller_->LockV1AppWithID(extension3_->id());
1297 EXPECT_EQ(5, model_->item_count());
1298 // Note that this not only checks the order of applications but also the
1300 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
1302 // Remember the current order of applications for the current user.
1303 const std::string& current_user_id =
1304 multi_user_util::GetUserIDFromProfile(profile());
1305 RememberUnpinnedRunningApplicationOrder();
1307 // Switch some items and check that restoring a user which was not yet
1308 // remembered changes nothing.
1310 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
1311 RestoreUnpinnedRunningApplicationOrder("second-fake-user@fake.com");
1312 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
1314 // Restoring the stored user should however do the right thing.
1315 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1316 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
1318 // Switch again some items and even delete one - making sure that the missing
1319 // item gets properly handled.
1321 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1322 EXPECT_EQ("AppList, Chrome, app3, app2", GetPinnedAppStatus());
1323 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1324 EXPECT_EQ("AppList, Chrome, app2, app3", GetPinnedAppStatus());
1326 // Check that removing more items does not crash and changes nothing.
1327 launcher_controller_->UnlockV1AppWithID(extension2_->id());
1328 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1329 EXPECT_EQ("AppList, Chrome, app3", GetPinnedAppStatus());
1330 launcher_controller_->UnlockV1AppWithID(extension3_->id());
1331 RestoreUnpinnedRunningApplicationOrder(current_user_id);
1332 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
1335 // Check that with multi profile V1 apps are properly added / removed from the
1337 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1338 V1AppUpdateOnUserSwitch) {
1339 // Create a browser item in the LauncherController.
1340 InitLauncherController();
1341 EXPECT_EQ(2, model_->item_count());
1343 // Create a "windowed gmail app".
1344 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1345 profile(), extension_misc::kGmailAppId, gmail_url));
1346 EXPECT_EQ(3, model_->item_count());
1348 // After switching to a second user the item should be gone.
1349 std::string user2 = "user2";
1350 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1351 SwitchActiveUser(profile2->GetProfileName());
1352 EXPECT_EQ(2, model_->item_count());
1354 // After switching back the item should be back.
1355 SwitchActiveUser(profile()->GetProfileName());
1356 EXPECT_EQ(3, model_->item_count());
1357 // Note we destroy now the gmail app with the closure end.
1359 EXPECT_EQ(2, model_->item_count());
1362 // Check edge cases with multi profile V1 apps in the shelf.
1363 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1364 V1AppUpdateOnUserSwitchEdgecases) {
1365 // Create a browser item in the LauncherController.
1366 InitLauncherController();
1368 // First test: Create an app when the user is not active.
1369 std::string user2 = "user2";
1370 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1372 // Create a "windowed gmail app".
1373 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1374 profile2, extension_misc::kGmailAppId, gmail_url));
1375 EXPECT_EQ(2, model_->item_count());
1377 // However - switching to the user should show it.
1378 SwitchActiveUser(profile2->GetProfileName());
1379 EXPECT_EQ(3, model_->item_count());
1381 // Second test: Remove the app when the user is not active and see that it
1383 SwitchActiveUser(profile()->GetProfileName());
1384 EXPECT_EQ(2, model_->item_count());
1385 // Note: the closure ends and the browser will go away.
1387 EXPECT_EQ(2, model_->item_count());
1388 SwitchActiveUser(profile2->GetProfileName());
1389 EXPECT_EQ(2, model_->item_count());
1390 SwitchActiveUser(profile()->GetProfileName());
1391 EXPECT_EQ(2, model_->item_count());
1394 // Check edge case where a visiting V1 app gets closed (crbug.com/321374).
1395 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1396 V1CloseOnVisitingDesktop) {
1397 // Create a browser item in the LauncherController.
1398 InitLauncherController();
1400 chrome::MultiUserWindowManager* manager =
1401 chrome::MultiUserWindowManager::GetInstance();
1403 // First create an app when the user is active.
1404 std::string user2 = "user2";
1405 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1407 // Create a "windowed gmail app".
1408 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1410 extension_misc::kGmailAppId,
1412 EXPECT_EQ(3, model_->item_count());
1414 // Transfer the app to the other screen and switch users.
1415 manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(),
1417 EXPECT_EQ(3, model_->item_count());
1418 SwitchActiveUser(profile2->GetProfileName());
1419 EXPECT_EQ(2, model_->item_count());
1421 // After the app was destroyed, switch back. (which caused already a crash).
1422 SwitchActiveUser(profile()->GetProfileName());
1424 // Create the same app again - which was also causing the crash.
1425 EXPECT_EQ(2, model_->item_count());
1427 // Create a "windowed gmail app".
1428 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1430 extension_misc::kGmailAppId,
1432 EXPECT_EQ(3, model_->item_count());
1434 SwitchActiveUser(profile2->GetProfileName());
1435 EXPECT_EQ(2, model_->item_count());
1438 // Check edge cases with multi profile V1 apps in the shelf.
1439 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1440 V1AppUpdateOnUserSwitchEdgecases2) {
1441 // Create a browser item in the LauncherController.
1442 InitLauncherController();
1443 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
1444 SetAppTabHelper(app_tab_helper);
1446 // First test: Create an app when the user is not active.
1447 std::string user2 = "user2";
1448 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1449 SwitchActiveUser(profile2->GetProfileName());
1451 // Create a "windowed gmail app".
1452 scoped_ptr<V1App> v1_app(CreateRunningV1App(
1453 profile(), extension_misc::kGmailAppId, gmail_url));
1454 EXPECT_EQ(2, model_->item_count());
1456 // However - switching to the user should show it.
1457 SwitchActiveUser(profile()->GetProfileName());
1458 EXPECT_EQ(3, model_->item_count());
1460 // Second test: Remove the app when the user is not active and see that it
1462 SwitchActiveUser(profile2->GetProfileName());
1463 EXPECT_EQ(2, model_->item_count());
1466 EXPECT_EQ(2, model_->item_count());
1467 SwitchActiveUser(profile()->GetProfileName());
1468 EXPECT_EQ(2, model_->item_count());
1469 SwitchActiveUser(profile2->GetProfileName());
1470 EXPECT_EQ(2, model_->item_count());
1473 // Check that activating an item which is on another user's desktop, will bring
1475 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1476 TestLauncherActivationPullsBackWindow) {
1477 // Create a browser item in the LauncherController.
1478 InitLauncherController();
1479 chrome::MultiUserWindowManager* manager =
1480 chrome::MultiUserWindowManager::GetInstance();
1482 // Add two users to the window manager.
1483 std::string user2 = "user2";
1484 TestingProfile* profile2 = CreateMultiUserProfile(user2);
1485 manager->AddUser(profile());
1486 manager->AddUser(profile2);
1487 const std::string& current_user =
1488 multi_user_util::GetUserIDFromProfile(profile());
1490 // Create a browser window with a native window for the current user.
1491 scoped_ptr<BrowserWindow> browser_window(CreateTestBrowserWindow(
1492 Browser::CreateParams(profile(), chrome::HOST_DESKTOP_TYPE_ASH)));
1493 aura::Window* window = browser_window->GetNativeWindow();
1494 manager->SetWindowOwner(window, current_user);
1496 // Check that an activation of the window on its owner's desktop does not
1497 // change the visibility to another user.
1498 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window.get(),
1500 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
1502 // Transfer the window to another user's desktop and check that activating it
1503 // does pull it back to that user.
1504 manager->ShowWindowForUser(window, user2);
1505 EXPECT_FALSE(manager->IsWindowOnDesktopOfUser(window, current_user));
1506 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window.get(),
1508 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
1512 // Check that lock -> pin -> unlock -> unpin does properly transition.
1513 TEST_F(ChromeLauncherControllerTest, CheckLockPinUnlockUnpin) {
1514 InitLauncherController();
1515 // Model should only contain the browser shortcut and app list items.
1516 EXPECT_EQ(2, model_->item_count());
1517 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1519 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1521 launcher_controller_->LockV1AppWithID(extension1_->id());
1523 EXPECT_EQ(3, model_->item_count());
1524 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type);
1525 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1526 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1528 launcher_controller_->PinAppWithID(extension1_->id());
1530 EXPECT_EQ(3, model_->item_count());
1531 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1532 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1534 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1536 launcher_controller_->UnlockV1AppWithID(extension1_->id());
1538 EXPECT_EQ(3, model_->item_count());
1539 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1540 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1542 launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
1544 launcher_controller_->UnpinAppWithID(extension1_->id());
1546 EXPECT_EQ(2, model_->item_count());
1549 // Check that a locked (windowed V1 application) will be properly converted
1550 // between locked and pinned when the order gets changed through a profile /
1552 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAndLockedAppsResyncOrder) {
1553 InitLauncherController();
1554 base::ListValue policy_value0;
1555 InsertPrefValue(&policy_value0, 0, extension1_->id());
1556 InsertPrefValue(&policy_value0, 1, extension3_->id());
1557 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1558 policy_value0.DeepCopy());
1559 // The shelf layout has always one static item at the beginning (App List).
1560 SetShelfChromeIconIndex(0);
1561 extension_service_->AddExtension(extension1_.get());
1562 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1563 extension_service_->AddExtension(extension2_.get());
1564 // No new app icon will be generated.
1565 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1566 // Add the app as locked app which will add it (un-pinned).
1567 launcher_controller_->LockV1AppWithID(extension2_->id());
1568 EXPECT_EQ("AppList, Chrome, App1, app2", GetPinnedAppStatus());
1569 extension_service_->AddExtension(extension3_.get());
1570 EXPECT_EQ("AppList, Chrome, App1, App3, app2", GetPinnedAppStatus());
1572 // Now request to pin all items which should convert the locked item into a
1574 base::ListValue policy_value1;
1575 InsertPrefValue(&policy_value1, 0, extension3_->id());
1576 InsertPrefValue(&policy_value1, 1, extension2_->id());
1577 InsertPrefValue(&policy_value1, 2, extension1_->id());
1578 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1579 policy_value1.DeepCopy());
1580 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1582 // Going back to a status where there is no requirement for app 2 to be pinned
1583 // should convert it back to locked but not pinned and state. The position
1584 // is determined by the |ShelfModel|'s weight system and since running
1585 // applications are not allowed to be mixed with shortcuts, it should show up
1586 // at the end of the list.
1587 base::ListValue policy_value2;
1588 InsertPrefValue(&policy_value2, 0, extension3_->id());
1589 InsertPrefValue(&policy_value2, 1, extension1_->id());
1590 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1591 policy_value2.DeepCopy());
1592 EXPECT_EQ("AppList, Chrome, App3, App1, app2", GetPinnedAppStatus());
1594 // Removing an item should simply close it and everything should shift.
1595 base::ListValue policy_value3;
1596 InsertPrefValue(&policy_value3, 0, extension3_->id());
1597 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1598 policy_value3.DeepCopy());
1599 EXPECT_EQ("AppList, Chrome, App3, app2", GetPinnedAppStatus());
1602 // Check that a running and not pinned V2 application will be properly converted
1603 // between locked and pinned when the order gets changed through a profile /
1605 TEST_F(ChromeLauncherControllerTest,
1606 RestoreDefaultAndRunningV2AppsResyncOrder) {
1607 InitLauncherController();
1608 base::ListValue policy_value0;
1609 InsertPrefValue(&policy_value0, 0, extension1_->id());
1610 InsertPrefValue(&policy_value0, 1, extension3_->id());
1611 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1612 policy_value0.DeepCopy());
1613 // The shelf layout has always one static item at the beginning (app List).
1614 SetShelfChromeIconIndex(0);
1615 extension_service_->AddExtension(extension1_.get());
1616 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1617 extension_service_->AddExtension(extension2_.get());
1618 // No new app icon will be generated.
1619 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus());
1620 // Add the app as an unpinned but running V2 app.
1621 CreateRunningV2App(extension2_->id());
1622 EXPECT_EQ("AppList, Chrome, App1, *app2", GetPinnedAppStatus());
1623 extension_service_->AddExtension(extension3_.get());
1624 EXPECT_EQ("AppList, Chrome, App1, App3, *app2", GetPinnedAppStatus());
1626 // Now request to pin all items which should convert the locked item into a
1628 base::ListValue policy_value1;
1629 InsertPrefValue(&policy_value1, 0, extension3_->id());
1630 InsertPrefValue(&policy_value1, 1, extension2_->id());
1631 InsertPrefValue(&policy_value1, 2, extension1_->id());
1632 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1633 policy_value1.DeepCopy());
1634 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus());
1636 // Going back to a status where there is no requirement for app 2 to be pinned
1637 // should convert it back to running V2 app. Since the position is determined
1638 // by the |ShelfModel|'s weight system, it will be after last pinned item.
1639 base::ListValue policy_value2;
1640 InsertPrefValue(&policy_value2, 0, extension3_->id());
1641 InsertPrefValue(&policy_value2, 1, extension1_->id());
1642 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1643 policy_value2.DeepCopy());
1644 EXPECT_EQ("AppList, Chrome, App3, App1, *app2", GetPinnedAppStatus());
1646 // Removing an item should simply close it and everything should shift.
1647 base::ListValue policy_value3;
1648 InsertPrefValue(&policy_value3, 0, extension3_->id());
1649 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1650 policy_value3.DeepCopy());
1651 EXPECT_EQ("AppList, Chrome, App3, *app2", GetPinnedAppStatus());
1654 // Each user has a different set of applications pinned. Check that when
1655 // switching between the two users, the state gets properly set.
1656 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestore) {
1657 base::ListValue user_a;
1658 base::ListValue user_b;
1659 SetUpMultiUserScenario(&user_a, &user_b);
1661 SetShelfChromeIconIndex(6);
1662 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1664 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1665 GetPinnedAppStatus());
1668 SetShelfChromeIconIndex(4);
1669 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1672 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus());
1674 // Switch back to 1.
1675 SetShelfChromeIconIndex(8);
1676 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1678 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1679 GetPinnedAppStatus());
1681 // Switch back to 2.
1682 SetShelfChromeIconIndex(4);
1683 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1685 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus());
1688 // Each user has a different set of applications pinned, and one user has an
1689 // application running. Check that when switching between the two users, the
1690 // state gets properly set.
1691 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestoreWithRunningV2App) {
1692 base::ListValue user_a;
1693 base::ListValue user_b;
1694 SetUpMultiUserScenario(&user_a, &user_b);
1696 // Run App1 and assume that it is a V2 app.
1697 CreateRunningV2App(extension1_->id());
1700 SetShelfChromeIconIndex(6);
1701 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1703 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1704 GetPinnedAppStatus());
1707 SetShelfChromeIconIndex(4);
1708 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1711 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus());
1713 // Switch back to 1.
1714 SetShelfChromeIconIndex(8);
1715 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1717 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome",
1718 GetPinnedAppStatus());
1720 // Switch back to 2.
1721 SetShelfChromeIconIndex(4);
1722 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1724 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus());
1727 // Each user has a different set of applications pinned, and one user has an
1728 // application running. The chrome icon is not the last item in the list.
1729 // Check that when switching between the two users, the state gets properly set.
1730 // There was once a bug associated with this.
1731 TEST_F(ChromeLauncherControllerTest,
1732 UserSwitchIconRestoreWithRunningV2AppChromeInMiddle) {
1733 base::ListValue user_a;
1734 base::ListValue user_b;
1735 SetUpMultiUserScenario(&user_a, &user_b);
1737 // Run App1 and assume that it is a V2 app.
1738 CreateRunningV2App(extension1_->id());
1741 SetShelfChromeIconIndex(5);
1742 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1744 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6",
1745 GetPinnedAppStatus());
1748 SetShelfChromeIconIndex(4);
1749 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1752 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus());
1754 // Switch back to 1.
1755 SetShelfChromeIconIndex(5);
1756 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1758 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6",
1759 GetPinnedAppStatus());
1762 TEST_F(ChromeLauncherControllerTest, Policy) {
1763 extension_service_->AddExtension(extension1_.get());
1764 extension_service_->AddExtension(extension3_.get());
1766 base::ListValue policy_value;
1767 InsertPrefValue(&policy_value, 0, extension1_->id());
1768 InsertPrefValue(&policy_value, 1, extension2_->id());
1769 profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
1770 policy_value.DeepCopy());
1772 // Only |extension1_| should get pinned. |extension2_| is specified but not
1773 // installed, and |extension3_| is part of the default set, but that shouldn't
1774 // take effect when the policy override is in place.
1775 InitLauncherController();
1776 EXPECT_EQ(3, model_->item_count());
1777 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1778 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1779 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
1780 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1782 // Installing |extension2_| should add it to the launcher.
1783 extension_service_->AddExtension(extension2_.get());
1784 EXPECT_EQ(4, model_->item_count());
1785 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1786 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[3].type);
1787 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
1788 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1789 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1791 // Removing |extension1_| from the policy should be reflected in the launcher.
1792 policy_value.Remove(0, NULL);
1793 profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
1794 policy_value.DeepCopy());
1795 EXPECT_EQ(3, model_->item_count());
1796 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
1797 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
1798 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
1799 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1802 TEST_F(ChromeLauncherControllerTest, UnpinWithUninstall) {
1803 extension_service_->AddExtension(extension3_.get());
1804 extension_service_->AddExtension(extension4_.get());
1806 InitLauncherController();
1808 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
1809 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
1811 extension_service_->UnloadExtension(extension3_->id(),
1812 UnloadedExtensionInfo::REASON_UNINSTALL);
1814 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
1815 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
1818 TEST_F(ChromeLauncherControllerTest, PrefUpdates) {
1819 extension_service_->AddExtension(extension2_.get());
1820 extension_service_->AddExtension(extension3_.get());
1821 extension_service_->AddExtension(extension4_.get());
1823 InitLauncherController();
1825 std::vector<std::string> expected_launchers;
1826 std::vector<std::string> actual_launchers;
1827 base::ListValue pref_value;
1828 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1829 pref_value.DeepCopy());
1830 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1831 EXPECT_EQ(expected_launchers, actual_launchers);
1833 // Unavailable extensions don't create launcher items.
1834 InsertPrefValue(&pref_value, 0, extension1_->id());
1835 InsertPrefValue(&pref_value, 1, extension2_->id());
1836 InsertPrefValue(&pref_value, 2, extension4_->id());
1837 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1838 pref_value.DeepCopy());
1839 expected_launchers.push_back(extension2_->id());
1840 expected_launchers.push_back(extension4_->id());
1841 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1842 EXPECT_EQ(expected_launchers, actual_launchers);
1844 // Redundant pref entries show up only once.
1845 InsertPrefValue(&pref_value, 2, extension3_->id());
1846 InsertPrefValue(&pref_value, 2, extension3_->id());
1847 InsertPrefValue(&pref_value, 5, extension3_->id());
1848 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1849 pref_value.DeepCopy());
1850 expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id());
1851 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1852 EXPECT_EQ(expected_launchers, actual_launchers);
1854 // Order changes are reflected correctly.
1856 InsertPrefValue(&pref_value, 0, extension4_->id());
1857 InsertPrefValue(&pref_value, 1, extension3_->id());
1858 InsertPrefValue(&pref_value, 2, extension2_->id());
1859 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1860 pref_value.DeepCopy());
1861 std::reverse(expected_launchers.begin(), expected_launchers.end());
1862 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1863 EXPECT_EQ(expected_launchers, actual_launchers);
1867 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1868 pref_value.DeepCopy());
1869 expected_launchers.clear();
1870 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1871 EXPECT_EQ(expected_launchers, actual_launchers);
1874 TEST_F(ChromeLauncherControllerTest, PendingInsertionOrder) {
1875 extension_service_->AddExtension(extension1_.get());
1876 extension_service_->AddExtension(extension3_.get());
1878 InitLauncherController();
1880 base::ListValue pref_value;
1881 InsertPrefValue(&pref_value, 0, extension1_->id());
1882 InsertPrefValue(&pref_value, 1, extension2_->id());
1883 InsertPrefValue(&pref_value, 2, extension3_->id());
1884 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
1885 pref_value.DeepCopy());
1887 std::vector<std::string> expected_launchers;
1888 expected_launchers.push_back(extension1_->id());
1889 expected_launchers.push_back(extension3_->id());
1890 std::vector<std::string> actual_launchers;
1892 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1893 EXPECT_EQ(expected_launchers, actual_launchers);
1895 // Install |extension2| and verify it shows up between the other two.
1896 extension_service_->AddExtension(extension2_.get());
1897 expected_launchers.insert(expected_launchers.begin() + 1, extension2_->id());
1898 GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
1899 EXPECT_EQ(expected_launchers, actual_launchers);
1902 // Checks the created menus and menu lists for correctness. It uses the given
1903 // |controller| to create the objects for the given |item| and checks the
1904 // found item count against the |expected_items|. The |title| list contains the
1905 // menu titles in the order of their appearance in the menu (not including the
1906 // application name).
1907 bool CheckMenuCreation(ChromeLauncherController* controller,
1908 const ash::ShelfItem& item,
1909 size_t expected_items,
1910 base::string16 title[],
1912 ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0);
1913 // A new behavior has been added: Only show menus if there is at least one
1915 if (expected_items < 1 && is_browser) {
1916 EXPECT_EQ(0u, items.size());
1917 return items.size() == 0;
1919 // There should be one item in there: The title.
1920 EXPECT_EQ(expected_items + 1, items.size());
1921 EXPECT_FALSE(items[0]->IsEnabled());
1922 for (size_t i = 0; i < expected_items; i++) {
1923 EXPECT_EQ(title[i], items[1 + i]->title());
1924 // Check that the first real item has a leading separator.
1926 EXPECT_TRUE(items[i]->HasLeadingSeparator());
1928 EXPECT_FALSE(items[i]->HasLeadingSeparator());
1931 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel(
1932 controller->GetApplicationList(item, 0)));
1933 // The first element in the menu is a spacing separator. On some systems
1934 // (e.g. Windows) such things do not exist. As such we check the existence
1935 // and adjust dynamically.
1936 int first_item = menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR ? 1 : 0;
1937 int expected_menu_items = first_item +
1938 (expected_items ? (expected_items + 3) : 2);
1939 EXPECT_EQ(expected_menu_items, menu->GetItemCount());
1940 EXPECT_FALSE(menu->IsEnabledAt(first_item));
1941 if (expected_items) {
1942 EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR,
1943 menu->GetTypeAt(first_item + 1));
1945 return items.size() == expected_items + 1;
1948 // Check that browsers get reflected correctly in the launcher menu.
1949 TEST_F(ChromeLauncherControllerTest, BrowserMenuGeneration) {
1950 EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
1951 chrome::NewTab(browser());
1953 InitLauncherController();
1955 // Check that the browser list is empty at this time.
1956 ash::ShelfItem item_browser;
1957 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
1959 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
1960 EXPECT_TRUE(CheckMenuCreation(
1961 launcher_controller_.get(), item_browser, 0, NULL, true));
1963 // Now make the created browser() visible by adding it to the active browser
1965 BrowserList::SetLastActive(browser());
1966 base::string16 title1 = ASCIIToUTF16("Test1");
1967 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
1968 base::string16 one_menu_item[] = { title1 };
1970 EXPECT_TRUE(CheckMenuCreation(
1971 launcher_controller_.get(), item_browser, 1, one_menu_item, true));
1973 // Create one more browser/window and check that one more was added.
1974 Browser::CreateParams ash_params(profile(), chrome::HOST_DESKTOP_TYPE_ASH);
1975 scoped_ptr<Browser> browser2(
1976 chrome::CreateBrowserWithTestWindowForParams(&ash_params));
1977 chrome::NewTab(browser2.get());
1978 BrowserList::SetLastActive(browser2.get());
1979 base::string16 title2 = ASCIIToUTF16("Test2");
1980 NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
1983 // Check that the list contains now two entries - make furthermore sure that
1984 // the active item is the first entry.
1985 base::string16 two_menu_items[] = {title1, title2};
1986 EXPECT_TRUE(CheckMenuCreation(
1987 launcher_controller_.get(), item_browser, 2, two_menu_items, true));
1989 // Apparently we have to close all tabs we have.
1990 chrome::CloseTab(browser2.get());
1993 #if defined(OS_CHROMEOS)
1994 // Check the multi profile case where only user related browsers should show
1996 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
1997 BrowserMenuGenerationTwoUsers) {
1998 // Create a browser item in the LauncherController.
1999 InitLauncherController();
2001 ash::ShelfItem item_browser;
2002 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2004 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2006 // Check that the menu is empty.
2007 chrome::NewTab(browser());
2008 EXPECT_TRUE(CheckMenuCreation(
2009 launcher_controller_.get(), item_browser, 0, NULL, true));
2011 // Show the created |browser()| by adding it to the active browser list.
2012 BrowserList::SetLastActive(browser());
2013 base::string16 title1 = ASCIIToUTF16("Test1");
2014 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
2015 base::string16 one_menu_item1[] = { title1 };
2016 EXPECT_TRUE(CheckMenuCreation(
2017 launcher_controller_.get(), item_browser, 1, one_menu_item1, true));
2019 // Create a browser for another user and check that it is not included in the
2020 // users running browser list.
2021 std::string user2 = "user2";
2022 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2023 scoped_ptr<Browser> browser2(
2024 CreateBrowserAndTabWithProfile(profile2, user2, "http://test2"));
2025 base::string16 one_menu_item2[] = { ASCIIToUTF16(user2) };
2026 EXPECT_TRUE(CheckMenuCreation(
2027 launcher_controller_.get(), item_browser, 1, one_menu_item1, true));
2029 // Switch to the other user and make sure that only that browser window gets
2031 SwitchActiveUser(profile2->GetProfileName());
2032 EXPECT_TRUE(CheckMenuCreation(
2033 launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
2035 // Transferred browsers of other users should not show up in the list.
2036 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
2037 browser()->window()->GetNativeWindow(),
2039 EXPECT_TRUE(CheckMenuCreation(
2040 launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
2042 chrome::CloseTab(browser2.get());
2044 #endif // defined(OS_CHROMEOS)
2046 // Check that V1 apps are correctly reflected in the launcher menu using the
2048 // Note that the extension matching logic is tested by the extension system
2049 // and does not need a separate test here.
2050 TEST_F(ChromeLauncherControllerTest, V1AppMenuGeneration) {
2051 EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
2052 EXPECT_EQ(0, browser()->tab_strip_model()->count());
2054 InitLauncherControllerWithBrowser();
2056 // Model should only contain the browser shortcut and app list items.
2057 EXPECT_EQ(2, model_->item_count());
2058 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
2060 // Installing |extension3_| adds it to the launcher.
2061 ash::ShelfID gmail_id = model_->next_id();
2062 extension_service_->AddExtension(extension3_.get());
2063 EXPECT_EQ(3, model_->item_count());
2064 int gmail_index = model_->ItemIndexByID(gmail_id);
2065 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2066 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2067 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2069 // Check the menu content.
2070 ash::ShelfItem item_browser;
2071 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2073 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2075 ash::ShelfItem item_gmail;
2076 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2077 item_gmail.id = gmail_id;
2078 EXPECT_TRUE(CheckMenuCreation(
2079 launcher_controller_.get(), item_gmail, 0, NULL, false));
2081 // Set the gmail URL to a new tab.
2082 base::string16 title1 = ASCIIToUTF16("Test1");
2083 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2085 base::string16 one_menu_item[] = { title1 };
2086 EXPECT_TRUE(CheckMenuCreation(
2087 launcher_controller_.get(), item_gmail, 1, one_menu_item, false));
2089 // Create one empty tab.
2090 chrome::NewTab(browser());
2091 base::string16 title2 = ASCIIToUTF16("Test2");
2092 NavigateAndCommitActiveTabWithTitle(
2094 GURL("https://bla"),
2097 // and another one with another gmail instance.
2098 chrome::NewTab(browser());
2099 base::string16 title3 = ASCIIToUTF16("Test3");
2100 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3);
2101 base::string16 two_menu_items[] = {title1, title3};
2102 EXPECT_TRUE(CheckMenuCreation(
2103 launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
2105 // Even though the item is in the V1 app list, it should also be in the
2107 base::string16 browser_menu_item[] = {title3};
2108 EXPECT_TRUE(CheckMenuCreation(
2109 launcher_controller_.get(), item_browser, 1, browser_menu_item, false));
2111 // Test that closing of (all) the item(s) does work (and all menus get
2112 // updated properly).
2113 launcher_controller_->Close(item_gmail.id);
2115 EXPECT_TRUE(CheckMenuCreation(
2116 launcher_controller_.get(), item_gmail, 0, NULL, false));
2117 base::string16 browser_menu_item2[] = { title2 };
2118 EXPECT_TRUE(CheckMenuCreation(
2119 launcher_controller_.get(), item_browser, 1, browser_menu_item2, false));
2122 #if defined(OS_CHROMEOS)
2123 // Check the multi profile case where only user related apps should show up.
2124 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2125 V1AppMenuGenerationTwoUsers) {
2126 // Create a browser item in the LauncherController.
2127 InitLauncherController();
2128 chrome::NewTab(browser());
2130 // Installing |extension3_| adds it to the launcher.
2131 ash::ShelfID gmail_id = model_->next_id();
2132 extension_service_->AddExtension(extension3_.get());
2133 EXPECT_EQ(3, model_->item_count());
2134 int gmail_index = model_->ItemIndexByID(gmail_id);
2135 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2136 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2137 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2139 // Check the menu content.
2140 ash::ShelfItem item_browser;
2141 item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
2143 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId);
2145 ash::ShelfItem item_gmail;
2146 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2147 item_gmail.id = gmail_id;
2148 EXPECT_TRUE(CheckMenuCreation(
2149 launcher_controller_.get(), item_gmail, 0, NULL, false));
2151 // Set the gmail URL to a new tab.
2152 base::string16 title1 = ASCIIToUTF16("Test1");
2153 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2155 base::string16 one_menu_item[] = { title1 };
2156 EXPECT_TRUE(CheckMenuCreation(
2157 launcher_controller_.get(), item_gmail, 1, one_menu_item, false));
2159 // Create a second profile and switch to that user.
2160 std::string user2 = "user2";
2161 TestingProfile* profile2 = CreateMultiUserProfile(user2);
2162 SwitchActiveUser(profile2->GetProfileName());
2164 // No item should have content yet.
2165 EXPECT_TRUE(CheckMenuCreation(
2166 launcher_controller_.get(), item_browser, 0, NULL, true));
2167 EXPECT_TRUE(CheckMenuCreation(
2168 launcher_controller_.get(), item_gmail, 0, NULL, false));
2170 // Transfer the browser of the first user - it should still not show up.
2171 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
2172 browser()->window()->GetNativeWindow(),
2175 EXPECT_TRUE(CheckMenuCreation(
2176 launcher_controller_.get(), item_browser, 0, NULL, true));
2177 EXPECT_TRUE(CheckMenuCreation(
2178 launcher_controller_.get(), item_gmail, 0, NULL, false));
2181 // Check that V2 applications are creating items properly in the launcher when
2182 // instantiated by the current user.
2183 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2184 V2AppHandlingTwoUsers) {
2185 InitLauncherController();
2186 // Create a profile for our second user (will be destroyed by the framework).
2187 TestingProfile* profile2 = CreateMultiUserProfile("user2");
2188 // Check that there is a browser and a app launcher.
2189 EXPECT_EQ(2, model_->item_count());
2192 V2App v2_app(profile(), extension1_);
2193 EXPECT_EQ(3, model_->item_count());
2195 // After switching users the item should go away.
2196 SwitchActiveUser(profile2->GetProfileName());
2197 EXPECT_EQ(2, model_->item_count());
2199 // And it should come back when switching back.
2200 SwitchActiveUser(profile()->GetProfileName());
2201 EXPECT_EQ(3, model_->item_count());
2204 // Check that V2 applications are creating items properly in edge cases:
2205 // a background user creates a V2 app, gets active and inactive again and then
2207 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2208 V2AppHandlingTwoUsersEdgeCases) {
2209 InitLauncherController();
2210 // Create a profile for our second user (will be destroyed by the framework).
2211 TestingProfile* profile2 = CreateMultiUserProfile("user2");
2212 // Check that there is a browser and a app launcher.
2213 EXPECT_EQ(2, model_->item_count());
2215 // Switch to an inactive user.
2216 SwitchActiveUser(profile2->GetProfileName());
2217 EXPECT_EQ(2, model_->item_count());
2219 // Add the v2 app to the inactive user and check that no item was added to
2222 V2App v2_app(profile(), extension1_);
2223 EXPECT_EQ(2, model_->item_count());
2225 // Switch to the primary user and check that the item is shown.
2226 SwitchActiveUser(profile()->GetProfileName());
2227 EXPECT_EQ(3, model_->item_count());
2229 // Switch to the second user and check that the item goes away - even if the
2230 // item gets closed.
2231 SwitchActiveUser(profile2->GetProfileName());
2232 EXPECT_EQ(2, model_->item_count());
2235 // After the application was killed there should be still 2 items.
2236 EXPECT_EQ(2, model_->item_count());
2238 // Switching then back to the default user should not show the additional item
2240 SwitchActiveUser(profile()->GetProfileName());
2241 EXPECT_EQ(2, model_->item_count());
2244 // Check that V2 applications will be made visible on the target desktop if
2245 // another window of the same type got previously teleported there.
2246 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2247 V2AppFollowsTeleportedWindow) {
2248 InitLauncherController();
2249 chrome::MultiUserWindowManager* manager =
2250 chrome::MultiUserWindowManager::GetInstance();
2252 // Create and add three users / profiles, and go to #1's desktop.
2253 TestingProfile* profile1 = CreateMultiUserProfile("user-1");
2254 TestingProfile* profile2 = CreateMultiUserProfile("user-2");
2255 TestingProfile* profile3 = CreateMultiUserProfile("user-3");
2256 SwitchActiveUser(profile1->GetProfileName());
2258 // A v2 app for user #1 should be shown first and get hidden when switching to
2260 V2App v2_app_1(profile1, extension1_);
2261 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2262 SwitchActiveUser(profile2->GetProfileName());
2263 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2265 // Add a v2 app for user #1 while on desktop #2 should not be shown.
2266 V2App v2_app_2(profile1, extension1_);
2267 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2268 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2270 // Teleport the app from user #1 to the desktop #2 should show it.
2271 manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(),
2272 profile2->GetProfileName());
2273 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2274 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2276 // Creating a new application for user #1 on desktop #2 should teleport it
2277 // there automatically.
2278 V2App v2_app_3(profile1, extension1_);
2279 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2280 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2281 EXPECT_TRUE(v2_app_3.window()->GetNativeWindow()->IsVisible());
2283 // Switching back to desktop#1 and creating an app for user #1 should move
2284 // the app on desktop #1.
2285 SwitchActiveUser(profile1->GetProfileName());
2286 V2App v2_app_4(profile1, extension1_);
2287 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2288 EXPECT_TRUE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2289 EXPECT_FALSE(v2_app_3.window()->GetNativeWindow()->IsVisible());
2290 EXPECT_TRUE(v2_app_4.window()->GetNativeWindow()->IsVisible());
2292 // Switching to desktop #3 and create an app for user #1 there should land on
2293 // his own desktop (#1).
2294 SwitchActiveUser(profile3->GetProfileName());
2295 V2App v2_app_5(profile1, extension1_);
2296 EXPECT_FALSE(v2_app_5.window()->GetNativeWindow()->IsVisible());
2297 SwitchActiveUser(profile1->GetProfileName());
2298 EXPECT_TRUE(v2_app_5.window()->GetNativeWindow()->IsVisible());
2300 // Switching to desktop #2, hiding the app window and creating an app should
2301 // teleport there automatically.
2302 SwitchActiveUser(profile2->GetProfileName());
2303 v2_app_1.window()->Hide();
2304 V2App v2_app_6(profile1, extension1_);
2305 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
2306 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
2307 EXPECT_TRUE(v2_app_6.window()->GetNativeWindow()->IsVisible());
2310 // Check that V2 applications hide correctly on the shelf when the app window
2312 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest,
2313 V2AppHiddenWindows) {
2314 InitLauncherController();
2316 TestingProfile* profile2 = CreateMultiUserProfile("user-2");
2317 SwitchActiveUser(profile()->GetProfileName());
2318 EXPECT_EQ(2, model_->item_count());
2320 V2App v2_app_1(profile(), extension1_);
2321 EXPECT_EQ(3, model_->item_count());
2323 // Hide and show the app.
2324 v2_app_1.window()->Hide();
2325 EXPECT_EQ(2, model_->item_count());
2327 v2_app_1.window()->Show(apps::AppWindow::SHOW_ACTIVE);
2328 EXPECT_EQ(3, model_->item_count());
2331 // Switch user, hide and show the app and switch back.
2332 SwitchActiveUser(profile2->GetProfileName());
2333 EXPECT_EQ(2, model_->item_count());
2335 v2_app_1.window()->Hide();
2336 EXPECT_EQ(2, model_->item_count());
2338 v2_app_1.window()->Show(apps::AppWindow::SHOW_ACTIVE);
2339 EXPECT_EQ(2, model_->item_count());
2341 SwitchActiveUser(profile()->GetProfileName());
2342 EXPECT_EQ(3, model_->item_count());
2345 // Switch user, hide the app, switch back and then show it again.
2346 SwitchActiveUser(profile2->GetProfileName());
2347 EXPECT_EQ(2, model_->item_count());
2349 v2_app_1.window()->Hide();
2350 EXPECT_EQ(2, model_->item_count());
2352 SwitchActiveUser(profile()->GetProfileName());
2353 EXPECT_EQ(2, model_->item_count());
2355 v2_app_1.window()->Show(apps::AppWindow::SHOW_ACTIVE);
2356 EXPECT_EQ(3, model_->item_count());
2359 // Create a second app, hide and show it and then hide both apps.
2360 V2App v2_app_2(profile(), extension1_);
2361 EXPECT_EQ(3, model_->item_count());
2363 v2_app_2.window()->Hide();
2364 EXPECT_EQ(3, model_->item_count());
2366 v2_app_2.window()->Show(apps::AppWindow::SHOW_ACTIVE);
2367 EXPECT_EQ(3, model_->item_count());
2369 v2_app_1.window()->Hide();
2370 v2_app_2.window()->Hide();
2371 EXPECT_EQ(2, model_->item_count());
2374 #endif // defined(OS_CHROMEOS)
2376 // Checks that the generated menu list properly activates items.
2377 TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) {
2378 InitLauncherControllerWithBrowser();
2380 // Add |extension3_| to the launcher and add two items.
2381 GURL gmail = GURL("https://mail.google.com/mail/u");
2382 ash::ShelfID gmail_id = model_->next_id();
2383 extension_service_->AddExtension(extension3_.get());
2384 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2385 base::string16 title1 = ASCIIToUTF16("Test1");
2386 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2387 chrome::NewTab(browser());
2388 base::string16 title2 = ASCIIToUTF16("Test2");
2389 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
2391 // Check that the menu is properly set.
2392 ash::ShelfItem item_gmail;
2393 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2394 item_gmail.id = gmail_id;
2395 base::string16 two_menu_items[] = {title1, title2};
2396 EXPECT_TRUE(CheckMenuCreation(
2397 launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
2398 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
2399 // Execute the second item in the list (which shouldn't do anything since that
2400 // item is per definition already the active tab).
2402 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel(
2403 launcher_controller_->GetApplicationList(item_gmail, 0)));
2404 // The first element in the menu is a spacing separator. On some systems
2405 // (e.g. Windows) such things do not exist. As such we check the existence
2406 // and adjust dynamically.
2408 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
2409 menu->ActivatedAt(first_item + 3);
2411 EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
2413 // Execute the first item.
2415 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel(
2416 launcher_controller_->GetApplicationList(item_gmail, 0)));
2418 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
2419 menu->ActivatedAt(first_item + 2);
2421 // Now the active tab should be the second item.
2422 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
2425 // Checks that the generated menu list properly deletes items.
2426 TEST_F(ChromeLauncherControllerTest, V1AppMenuDeletionExecution) {
2427 InitLauncherControllerWithBrowser();
2429 // Add |extension3_| to the launcher and add two items.
2430 GURL gmail = GURL("https://mail.google.com/mail/u");
2431 ash::ShelfID gmail_id = model_->next_id();
2432 extension_service_->AddExtension(extension3_.get());
2433 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
2434 base::string16 title1 = ASCIIToUTF16("Test1");
2435 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
2436 chrome::NewTab(browser());
2437 base::string16 title2 = ASCIIToUTF16("Test2");
2438 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
2440 // Check that the menu is properly set.
2441 ash::ShelfItem item_gmail;
2442 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2443 item_gmail.id = gmail_id;
2444 base::string16 two_menu_items[] = {title1, title2};
2445 EXPECT_TRUE(CheckMenuCreation(
2446 launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
2448 int tabs = browser()->tab_strip_model()->count();
2449 // Activate the proper tab through the menu item.
2451 ChromeLauncherAppMenuItems items =
2452 launcher_controller_->GetApplicationList(item_gmail, 0);
2453 items[1]->Execute(0);
2454 EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
2457 // Delete one tab through the menu item.
2459 ChromeLauncherAppMenuItems items =
2460 launcher_controller_->GetApplicationList(item_gmail, 0);
2461 items[1]->Execute(ui::EF_SHIFT_DOWN);
2462 EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
2466 // Tests that panels create launcher items correctly
2467 TEST_F(ChromeLauncherControllerTest, AppPanels) {
2468 InitLauncherControllerWithBrowser();
2469 // App list and Browser shortcut ShelfItems are added.
2470 EXPECT_EQ(2, model_observer_->added());
2472 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl();
2473 SetAppIconLoader(app_icon_loader);
2475 // Test adding an app panel
2476 std::string app_id = extension1_->id();
2477 AppWindowLauncherItemController* app_panel_controller =
2478 new AppWindowLauncherItemController(
2479 LauncherItemController::TYPE_APP_PANEL,
2482 launcher_controller_.get());
2483 ash::ShelfID shelf_id1 = launcher_controller_->CreateAppLauncherItem(
2484 app_panel_controller, app_id, ash::STATUS_RUNNING);
2485 int panel_index = model_observer_->last_index();
2486 EXPECT_EQ(3, model_observer_->added());
2487 EXPECT_EQ(0, model_observer_->changed());
2488 EXPECT_EQ(1, app_icon_loader->fetch_count());
2489 model_observer_->clear_counts();
2491 // App panels should have a separate identifier than the app id
2492 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(app_id));
2494 // Setting the app image image should not change the panel if it set its icon
2495 app_panel_controller->set_image_set_by_controller(true);
2496 gfx::ImageSkia image;
2497 launcher_controller_->SetAppImage(app_id, image);
2498 EXPECT_EQ(0, model_observer_->changed());
2499 model_observer_->clear_counts();
2501 // Add a second app panel and verify that it get the same index as the first
2502 // one had, being added to the left of the existing panel.
2503 AppWindowLauncherItemController* app_panel_controller2 =
2504 new AppWindowLauncherItemController(
2505 LauncherItemController::TYPE_APP_PANEL,
2508 launcher_controller_.get());
2510 ash::ShelfID shelf_id2 = launcher_controller_->CreateAppLauncherItem(
2511 app_panel_controller2, app_id, ash::STATUS_RUNNING);
2512 EXPECT_EQ(panel_index, model_observer_->last_index());
2513 EXPECT_EQ(1, model_observer_->added());
2514 model_observer_->clear_counts();
2516 launcher_controller_->CloseLauncherItem(shelf_id2);
2517 launcher_controller_->CloseLauncherItem(shelf_id1);
2518 EXPECT_EQ(2, model_observer_->removed());
2521 // Tests that the Gmail extension matches more then the app itself claims with
2522 // the manifest file.
2523 TEST_F(ChromeLauncherControllerTest, GmailMatching) {
2524 InitLauncherControllerWithBrowser();
2526 // Create a Gmail browser tab.
2527 chrome::NewTab(browser());
2528 base::string16 title = ASCIIToUTF16("Test");
2529 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title);
2530 content::WebContents* content =
2531 browser()->tab_strip_model()->GetActiveWebContents();
2533 // Check that the launcher controller does not recognize the running app.
2534 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
2536 // Installing |extension3_| adds it to the launcher.
2537 ash::ShelfID gmail_id = model_->next_id();
2538 extension_service_->AddExtension(extension3_.get());
2539 EXPECT_EQ(3, model_->item_count());
2540 int gmail_index = model_->ItemIndexByID(gmail_id);
2541 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2542 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2544 // Check that it is now handled.
2545 EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
2547 // Check also that the app has detected that properly.
2548 ash::ShelfItem item_gmail;
2549 item_gmail.type = ash::TYPE_APP_SHORTCUT;
2550 item_gmail.id = gmail_id;
2551 EXPECT_EQ(2U, launcher_controller_->GetApplicationList(item_gmail, 0).size());
2554 // Tests that the Gmail extension does not match the offline verison.
2555 TEST_F(ChromeLauncherControllerTest, GmailOfflineMatching) {
2556 InitLauncherControllerWithBrowser();
2558 // Create a Gmail browser tab.
2559 chrome::NewTab(browser());
2560 base::string16 title = ASCIIToUTF16("Test");
2561 NavigateAndCommitActiveTabWithTitle(browser(),
2562 GURL(offline_gmail_url),
2564 content::WebContents* content =
2565 browser()->tab_strip_model()->GetActiveWebContents();
2567 // Installing |extension3_| adds it to the launcher.
2568 ash::ShelfID gmail_id = model_->next_id();
2569 extension_service_->AddExtension(extension3_.get());
2570 EXPECT_EQ(3, model_->item_count());
2571 int gmail_index = model_->ItemIndexByID(gmail_id);
2572 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type);
2573 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
2575 // The content should not be able to be handled by the app.
2576 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
2579 // Verify that the launcher item positions are persisted and restored.
2580 TEST_F(ChromeLauncherControllerTest, PersistLauncherItemPositions) {
2581 InitLauncherController();
2583 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
2584 SetAppTabHelper(app_tab_helper);
2586 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2587 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
2589 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2590 EXPECT_EQ(0, tab_strip_model->count());
2591 chrome::NewTab(browser());
2592 chrome::NewTab(browser());
2593 EXPECT_EQ(2, tab_strip_model->count());
2594 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2595 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
2597 EXPECT_FALSE(launcher_controller_->IsAppPinned("1"));
2598 launcher_controller_->PinAppWithID("1");
2599 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
2600 launcher_controller_->PinAppWithID("2");
2602 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2603 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
2604 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
2605 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[3].type);
2607 // Move browser shortcut item from index 1 to index 3.
2609 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2610 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
2611 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
2612 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
2614 launcher_controller_.reset();
2615 if (!ash::Shell::HasInstance()) {
2616 delete item_delegate_manager_;
2618 // Clear already registered ShelfItemDelegate.
2619 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_);
2620 test.RemoveAllShelfItemDelegateForTest();
2622 model_.reset(new ash::ShelfModel);
2624 AddAppListLauncherItem();
2625 launcher_controller_.reset(
2626 ChromeLauncherController::CreateInstance(profile(), model_.get()));
2627 app_tab_helper = new TestAppTabHelperImpl;
2628 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2629 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
2630 SetAppTabHelper(app_tab_helper);
2631 if (!ash::Shell::HasInstance()) {
2632 item_delegate_manager_ = new ash::ShelfItemDelegateManager(model_.get());
2633 SetShelfItemDelegateManager(item_delegate_manager_);
2635 launcher_controller_->Init();
2637 // Check ShelfItems are restored after resetting ChromeLauncherController.
2638 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
2639 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
2640 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
2641 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
2644 // Verifies pinned apps are persisted and restored.
2645 TEST_F(ChromeLauncherControllerTest, PersistPinned) {
2646 InitLauncherControllerWithBrowser();
2647 size_t initial_size = model_->items().size();
2649 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2650 EXPECT_EQ(1, tab_strip_model->count());
2652 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
2653 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2654 SetAppTabHelper(app_tab_helper);
2656 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl;
2657 SetAppIconLoader(app_icon_loader);
2658 EXPECT_EQ(0, app_icon_loader->fetch_count());
2660 launcher_controller_->PinAppWithID("1");
2661 ash::ShelfID id = launcher_controller_->GetShelfIDForAppID("1");
2662 int app_index = model_->ItemIndexByID(id);
2663 EXPECT_EQ(1, app_icon_loader->fetch_count());
2664 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type);
2665 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
2666 EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
2667 EXPECT_EQ(initial_size + 1, model_->items().size());
2669 launcher_controller_.reset();
2670 if (!ash::Shell::HasInstance()) {
2671 delete item_delegate_manager_;
2673 // Clear already registered ShelfItemDelegate.
2674 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_);
2675 test.RemoveAllShelfItemDelegateForTest();
2677 model_.reset(new ash::ShelfModel);
2679 AddAppListLauncherItem();
2680 launcher_controller_.reset(
2681 ChromeLauncherController::CreateInstance(profile(), model_.get()));
2682 app_tab_helper = new TestAppTabHelperImpl;
2683 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
2684 SetAppTabHelper(app_tab_helper);
2685 app_icon_loader = new TestAppIconLoaderImpl;
2686 SetAppIconLoader(app_icon_loader);
2687 if (!ash::Shell::HasInstance()) {
2688 item_delegate_manager_ = new ash::ShelfItemDelegateManager(model_.get());
2689 SetShelfItemDelegateManager(item_delegate_manager_);
2691 launcher_controller_->Init();
2693 EXPECT_EQ(1, app_icon_loader->fetch_count());
2694 ASSERT_EQ(initial_size + 1, model_->items().size());
2695 EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
2696 EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
2697 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type);
2699 launcher_controller_->UnpinAppWithID("1");
2700 ASSERT_EQ(initial_size, model_->items().size());