1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 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" 48 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/ui/apps/chrome_app_window_delegate.h" 57 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h" 58 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h" 59 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" 60 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" 61 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h" 62 #include "chrome/common/chrome_constants.h" 63 #include "chrome/common/chrome_switches.h" 64 #include "chrome/test/base/testing_browser_process.h" 65 #include "chrome/test/base/testing_profile_manager.h" 66 #include "content/public/browser/web_contents_observer.h" 67 #include "content/public/test/test_utils.h" 68 #include "ui/aura/window.h" 69 #endif 70 71 using base::ASCIIToUTF16; 72 using extensions::Extension; 73 using extensions::Manifest; 74 using extensions::UnloadedExtensionInfo; 75 76 namespace { 77 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u"; 78 const char* gmail_url = "https://mail.google.com/mail/u"; 79 const char* kGmailLaunchURL = "https://mail.google.com/mail/ca"; 80 81 #if defined(OS_CHROMEOS) 82 // As defined in /chromeos/dbus/cryptohome_client.cc. 83 const char kUserIdHashSuffix[] = "-hash"; 84 85 // An extension prefix. 86 const char kCrxAppPrefix[] = "_crx_"; 87 #endif 88 89 // ShelfModelObserver implementation that tracks what messages are invoked. 90 class TestShelfModelObserver : public ash::ShelfModelObserver { 91 public: 92 TestShelfModelObserver() 93 : added_(0), 94 removed_(0), 95 changed_(0) { 96 } 97 98 virtual ~TestShelfModelObserver() { 99 } 100 101 // Overridden from ash::ShelfModelObserver: 102 virtual void ShelfItemAdded(int index) OVERRIDE { 103 ++added_; 104 last_index_ = index; 105 } 106 107 virtual void ShelfItemRemoved(int index, ash::ShelfID id) OVERRIDE { 108 ++removed_; 109 last_index_ = index; 110 } 111 112 virtual void ShelfItemChanged(int index, 113 const ash::ShelfItem& old_item) OVERRIDE { 114 ++changed_; 115 last_index_ = index; 116 } 117 118 virtual void ShelfItemMoved(int start_index, int target_index) OVERRIDE { 119 last_index_ = target_index; 120 } 121 122 virtual void ShelfStatusChanged() OVERRIDE { 123 } 124 125 void clear_counts() { 126 added_ = 0; 127 removed_ = 0; 128 changed_ = 0; 129 last_index_ = 0; 130 } 131 132 int added() const { return added_; } 133 int removed() const { return removed_; } 134 int changed() const { return changed_; } 135 int last_index() const { return last_index_; } 136 137 private: 138 int added_; 139 int removed_; 140 int changed_; 141 int last_index_; 142 143 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver); 144 }; 145 146 // Test implementation of AppIconLoader. 147 class TestAppIconLoaderImpl : public extensions::AppIconLoader { 148 public: 149 TestAppIconLoaderImpl() : fetch_count_(0) { 150 } 151 152 virtual ~TestAppIconLoaderImpl() { 153 } 154 155 // AppIconLoader implementation: 156 virtual void FetchImage(const std::string& id) OVERRIDE { 157 ++fetch_count_; 158 } 159 160 virtual void ClearImage(const std::string& id) OVERRIDE { 161 } 162 163 virtual void UpdateImage(const std::string& id) OVERRIDE { 164 } 165 166 int fetch_count() const { return fetch_count_; } 167 168 private: 169 int fetch_count_; 170 171 DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl); 172 }; 173 174 // Test implementation of AppTabHelper. 175 class TestAppTabHelperImpl : public ChromeLauncherController::AppTabHelper { 176 public: 177 TestAppTabHelperImpl() {} 178 virtual ~TestAppTabHelperImpl() {} 179 180 // Sets the id for the specified tab. The id is removed if Remove() is 181 // invoked. 182 void SetAppID(content::WebContents* tab, const std::string& id) { 183 tab_id_map_[tab] = id; 184 } 185 186 // Returns true if there is an id registered for |tab|. 187 bool HasAppID(content::WebContents* tab) const { 188 return tab_id_map_.find(tab) != tab_id_map_.end(); 189 } 190 191 // AppTabHelper implementation: 192 virtual std::string GetAppID(content::WebContents* tab) OVERRIDE { 193 return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] : 194 std::string(); 195 } 196 197 virtual bool IsValidIDForCurrentUser(const std::string& id) OVERRIDE { 198 for (TabToStringMap::const_iterator i = tab_id_map_.begin(); 199 i != tab_id_map_.end(); ++i) { 200 if (i->second == id) 201 return true; 202 } 203 return false; 204 } 205 206 virtual void SetCurrentUser(Profile* profile) OVERRIDE { 207 // We can ignore this for now. 208 } 209 210 private: 211 typedef std::map<content::WebContents*, std::string> TabToStringMap; 212 213 TabToStringMap tab_id_map_; 214 215 DISALLOW_COPY_AND_ASSIGN(TestAppTabHelperImpl); 216 }; 217 218 // Test implementation of a V2 app launcher item controller. 219 class TestV2AppLauncherItemController : public LauncherItemController { 220 public: 221 TestV2AppLauncherItemController(const std::string& app_id, 222 ChromeLauncherController* controller) 223 : LauncherItemController(LauncherItemController::TYPE_APP, 224 app_id, 225 controller) { 226 } 227 228 virtual ~TestV2AppLauncherItemController() {} 229 230 // Override for LauncherItemController: 231 virtual bool IsOpen() const OVERRIDE { return true; } 232 virtual bool IsVisible() const OVERRIDE { return true; } 233 virtual void Launch(ash::LaunchSource source, int event_flags) OVERRIDE {} 234 virtual bool Activate(ash::LaunchSource source) OVERRIDE { return false; } 235 virtual void Close() OVERRIDE {} 236 virtual bool ItemSelected(const ui::Event& event) OVERRIDE { return false; } 237 virtual base::string16 GetTitle() OVERRIDE { return base::string16(); } 238 virtual ChromeLauncherAppMenuItems GetApplicationList( 239 int event_flags) OVERRIDE { 240 ChromeLauncherAppMenuItems items; 241 items.push_back( 242 new ChromeLauncherAppMenuItem(base::string16(), NULL, false)); 243 items.push_back( 244 new ChromeLauncherAppMenuItem(base::string16(), NULL, false)); 245 return items.Pass(); 246 } 247 virtual ui::MenuModel* CreateContextMenu(aura::Window* root_window) OVERRIDE { 248 return NULL; 249 } 250 virtual ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) OVERRIDE { 251 return NULL; 252 } 253 virtual bool IsDraggable() OVERRIDE { return false; } 254 virtual bool ShouldShowTooltip() OVERRIDE { return false; } 255 256 private: 257 DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController); 258 }; 259 260 } // namespace 261 262 class ChromeLauncherControllerTest : public BrowserWithTestWindowTest { 263 protected: 264 ChromeLauncherControllerTest() 265 : BrowserWithTestWindowTest( 266 Browser::TYPE_TABBED, 267 chrome::HOST_DESKTOP_TYPE_ASH, 268 false), 269 test_controller_(NULL), 270 extension_service_(NULL) { 271 } 272 273 virtual ~ChromeLauncherControllerTest() { 274 } 275 276 virtual void SetUp() OVERRIDE { 277 BrowserWithTestWindowTest::SetUp(); 278 279 model_.reset(new ash::ShelfModel); 280 model_observer_.reset(new TestShelfModelObserver); 281 model_->AddObserver(model_observer_.get()); 282 283 if (ash::Shell::HasInstance()) { 284 item_delegate_manager_ = 285 ash::Shell::GetInstance()->shelf_item_delegate_manager(); 286 } else { 287 item_delegate_manager_ = 288 new ash::ShelfItemDelegateManager(model_.get()); 289 } 290 291 base::DictionaryValue manifest; 292 manifest.SetString(extensions::manifest_keys::kName, 293 "launcher controller test extension"); 294 manifest.SetString(extensions::manifest_keys::kVersion, "1"); 295 manifest.SetString(extensions::manifest_keys::kDescription, 296 "for testing pinned apps"); 297 298 extensions::TestExtensionSystem* extension_system( 299 static_cast<extensions::TestExtensionSystem*>( 300 extensions::ExtensionSystem::Get(profile()))); 301 extension_service_ = extension_system->CreateExtensionService( 302 CommandLine::ForCurrentProcess(), base::FilePath(), false); 303 304 std::string error; 305 extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 306 manifest, 307 Extension::NO_FLAGS, 308 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 309 &error); 310 extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 311 manifest, 312 Extension::NO_FLAGS, 313 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 314 &error); 315 // Fake gmail extension. 316 base::DictionaryValue manifest_gmail; 317 manifest_gmail.SetString(extensions::manifest_keys::kName, 318 "Gmail launcher controller test extension"); 319 manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1"); 320 manifest_gmail.SetString(extensions::manifest_keys::kDescription, 321 "for testing pinned Gmail"); 322 manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL, 323 kGmailLaunchURL); 324 base::ListValue* list = new base::ListValue(); 325 list->Append(base::Value::CreateStringValue("*://mail.google.com/mail/ca")); 326 manifest_gmail.Set(extensions::manifest_keys::kWebURLs, list); 327 328 extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 329 manifest_gmail, 330 Extension::NO_FLAGS, 331 extension_misc::kGmailAppId, 332 &error); 333 334 // Fake search extension. 335 extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 336 manifest, 337 Extension::NO_FLAGS, 338 extension_misc::kGoogleSearchAppId, 339 &error); 340 extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 341 manifest, 342 Extension::NO_FLAGS, 343 "cccccccccccccccccccccccccccccccc", 344 &error); 345 extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 346 manifest, 347 Extension::NO_FLAGS, 348 "dddddddddddddddddddddddddddddddd", 349 &error); 350 extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 351 manifest, 352 Extension::NO_FLAGS, 353 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", 354 &error); 355 extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, 356 manifest, 357 Extension::NO_FLAGS, 358 "ffffffffffffffffffffffffffffffff", 359 &error); 360 } 361 362 // Creates a running V2 app (not pinned) of type |app_id|. 363 virtual void CreateRunningV2App(const std::string& app_id) { 364 DCHECK(!test_controller_); 365 ash::ShelfID id = 366 launcher_controller_->CreateAppShortcutLauncherItemWithType( 367 app_id, 368 model_->item_count(), 369 ash::TYPE_PLATFORM_APP); 370 DCHECK(id); 371 // Change the created launcher controller into a V2 app controller. 372 test_controller_ = new TestV2AppLauncherItemController(app_id, 373 launcher_controller_.get()); 374 launcher_controller_->SetItemController(id, test_controller_); 375 } 376 377 // Sets the stage for a multi user test. 378 virtual void SetUpMultiUserScenario(base::ListValue* user_a, 379 base::ListValue* user_b) { 380 InitLauncherController(); 381 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); 382 383 // Set an empty pinned pref to begin with. 384 base::ListValue no_user; 385 SetShelfChromeIconIndex(0); 386 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 387 no_user.DeepCopy()); 388 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); 389 390 // Assume all applications have been added already. 391 extension_service_->AddExtension(extension1_.get()); 392 extension_service_->AddExtension(extension2_.get()); 393 extension_service_->AddExtension(extension3_.get()); 394 extension_service_->AddExtension(extension4_.get()); 395 extension_service_->AddExtension(extension5_.get()); 396 extension_service_->AddExtension(extension6_.get()); 397 extension_service_->AddExtension(extension7_.get()); 398 extension_service_->AddExtension(extension8_.get()); 399 // There should be nothing in the list by now. 400 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); 401 402 // Set user a preferences. 403 InsertPrefValue(user_a, 0, extension1_->id()); 404 InsertPrefValue(user_a, 1, extension2_->id()); 405 InsertPrefValue(user_a, 2, extension3_->id()); 406 InsertPrefValue(user_a, 3, extension4_->id()); 407 InsertPrefValue(user_a, 4, extension5_->id()); 408 InsertPrefValue(user_a, 5, extension6_->id()); 409 410 // Set user b preferences. 411 InsertPrefValue(user_b, 0, extension7_->id()); 412 InsertPrefValue(user_b, 1, extension8_->id()); 413 } 414 415 virtual void TearDown() OVERRIDE { 416 if (!ash::Shell::HasInstance()) 417 delete item_delegate_manager_; 418 model_->RemoveObserver(model_observer_.get()); 419 model_observer_.reset(); 420 launcher_controller_.reset(); 421 model_.reset(); 422 423 BrowserWithTestWindowTest::TearDown(); 424 } 425 426 void AddAppListLauncherItem() { 427 ash::ShelfItem app_list; 428 app_list.type = ash::TYPE_APP_LIST; 429 model_->Add(app_list); 430 } 431 432 void InitLauncherController() { 433 AddAppListLauncherItem(); 434 launcher_controller_.reset( 435 new ChromeLauncherController(profile(), model_.get())); 436 if (!ash::Shell::HasInstance()) 437 SetShelfItemDelegateManager(item_delegate_manager_); 438 launcher_controller_->Init(); 439 } 440 441 void InitLauncherControllerWithBrowser() { 442 chrome::NewTab(browser()); 443 BrowserList::SetLastActive(browser()); 444 InitLauncherController(); 445 } 446 447 void SetAppIconLoader(extensions::AppIconLoader* loader) { 448 launcher_controller_->SetAppIconLoaderForTest(loader); 449 } 450 451 void SetAppTabHelper(ChromeLauncherController::AppTabHelper* helper) { 452 launcher_controller_->SetAppTabHelperForTest(helper); 453 } 454 455 void SetShelfItemDelegateManager(ash::ShelfItemDelegateManager* manager) { 456 launcher_controller_->SetShelfItemDelegateManagerForTest(manager); 457 } 458 459 void InsertPrefValue(base::ListValue* pref_value, 460 int index, 461 const std::string& extension_id) { 462 base::DictionaryValue* entry = new base::DictionaryValue(); 463 entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id); 464 pref_value->Insert(index, entry); 465 } 466 467 // Gets the currently configured app launchers from the controller. 468 void GetAppLaunchers(ChromeLauncherController* controller, 469 std::vector<std::string>* launchers) { 470 launchers->clear(); 471 for (ash::ShelfItems::const_iterator iter(model_->items().begin()); 472 iter != model_->items().end(); ++iter) { 473 ChromeLauncherController::IDToItemControllerMap::const_iterator 474 entry(controller->id_to_item_controller_map_.find(iter->id)); 475 if (iter->type == ash::TYPE_APP_SHORTCUT && 476 entry != controller->id_to_item_controller_map_.end()) { 477 launchers->push_back(entry->second->app_id()); 478 } 479 } 480 } 481 482 // Get the setup of the currently shown launcher items in one string. 483 // Each pinned element will start with a big letter, each running but not 484 // pinned V1 app will start with a small letter and each running but not 485 // pinned V2 app will start with a '*' + small letter. 486 std::string GetPinnedAppStatus() { 487 std::string result; 488 for (int i = 0; i < model_->item_count(); i++) { 489 if (!result.empty()) 490 result.append(", "); 491 switch (model_->items()[i].type) { 492 case ash::TYPE_PLATFORM_APP: 493 result+= "*"; 494 // FALLTHROUGH 495 case ash::TYPE_WINDOWED_APP: { 496 const std::string& app = 497 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id); 498 if (app == extension1_->id()) { 499 result += "app1"; 500 EXPECT_FALSE( 501 launcher_controller_->IsAppPinned(extension1_->id())); 502 } else if (app == extension2_->id()) { 503 result += "app2"; 504 EXPECT_FALSE( 505 launcher_controller_->IsAppPinned(extension2_->id())); 506 } else if (app == extension3_->id()) { 507 result += "app3"; 508 EXPECT_FALSE( 509 launcher_controller_->IsAppPinned(extension3_->id())); 510 } else if (app == extension4_->id()) { 511 result += "app4"; 512 EXPECT_FALSE( 513 launcher_controller_->IsAppPinned(extension4_->id())); 514 } else if (app == extension5_->id()) { 515 result += "app5"; 516 EXPECT_FALSE( 517 launcher_controller_->IsAppPinned(extension5_->id())); 518 } else if (app == extension6_->id()) { 519 result += "app6"; 520 EXPECT_FALSE( 521 launcher_controller_->IsAppPinned(extension6_->id())); 522 } else if (app == extension7_->id()) { 523 result += "app7"; 524 EXPECT_FALSE( 525 launcher_controller_->IsAppPinned(extension7_->id())); 526 } else if (app == extension8_->id()) { 527 result += "app8"; 528 EXPECT_FALSE( 529 launcher_controller_->IsAppPinned(extension8_->id())); 530 } else { 531 result += "unknown"; 532 } 533 break; 534 } 535 case ash::TYPE_APP_SHORTCUT: { 536 const std::string& app = 537 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id); 538 if (app == extension1_->id()) { 539 result += "App1"; 540 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); 541 } else if (app == extension2_->id()) { 542 result += "App2"; 543 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id())); 544 } else if (app == extension3_->id()) { 545 result += "App3"; 546 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); 547 } else if (app == extension4_->id()) { 548 result += "App4"; 549 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); 550 } else if (app == extension5_->id()) { 551 result += "App5"; 552 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension5_->id())); 553 } else if (app == extension6_->id()) { 554 result += "App6"; 555 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension6_->id())); 556 } else if (app == extension7_->id()) { 557 result += "App7"; 558 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension7_->id())); 559 } else if (app == extension8_->id()) { 560 result += "App8"; 561 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension8_->id())); 562 } else { 563 result += "unknown"; 564 } 565 break; 566 } 567 case ash::TYPE_BROWSER_SHORTCUT: 568 result += "Chrome"; 569 break; 570 case ash::TYPE_APP_LIST: 571 result += "AppList"; 572 break; 573 default: 574 result += "Unknown"; 575 break; 576 } 577 } 578 return result; 579 } 580 581 // Set the index at which the chrome icon should be. 582 void SetShelfChromeIconIndex(int index) { 583 profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex, 584 index); 585 } 586 587 // Remember the order of unpinned but running applications for the current 588 // user. 589 void RememberUnpinnedRunningApplicationOrder() { 590 launcher_controller_->RememberUnpinnedRunningApplicationOrder(); 591 } 592 593 // Restore the order of running but unpinned applications for a given user. 594 void RestoreUnpinnedRunningApplicationOrder(const std::string& user_id) { 595 launcher_controller_->RestoreUnpinnedRunningApplicationOrder(user_id); 596 } 597 598 // Needed for extension service & friends to work. 599 scoped_refptr<Extension> extension1_; 600 scoped_refptr<Extension> extension2_; 601 scoped_refptr<Extension> extension3_; 602 scoped_refptr<Extension> extension4_; 603 scoped_refptr<Extension> extension5_; 604 scoped_refptr<Extension> extension6_; 605 scoped_refptr<Extension> extension7_; 606 scoped_refptr<Extension> extension8_; 607 scoped_ptr<ChromeLauncherController> launcher_controller_; 608 scoped_ptr<TestShelfModelObserver> model_observer_; 609 scoped_ptr<ash::ShelfModel> model_; 610 611 // |item_delegate_manager_| owns |test_controller_|. 612 LauncherItemController* test_controller_; 613 614 ExtensionService* extension_service_; 615 616 ash::ShelfItemDelegateManager* item_delegate_manager_; 617 618 private: 619 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerTest); 620 }; 621 622 #if defined(OS_CHROMEOS) 623 // A browser window proxy which is able to associate an aura native window with 624 // it. 625 class TestBrowserWindowAura : public TestBrowserWindow { 626 public: 627 // |native_window| will still be owned by the caller after the constructor 628 // was called. 629 explicit TestBrowserWindowAura(aura::Window* native_window) 630 : native_window_(native_window) { 631 } 632 virtual ~TestBrowserWindowAura() {} 633 634 virtual gfx::NativeWindow GetNativeWindow() OVERRIDE { 635 return native_window_.get(); 636 } 637 638 Browser* browser() { return browser_.get(); } 639 640 void CreateBrowser(const Browser::CreateParams& params) { 641 Browser::CreateParams create_params = params; 642 create_params.window = this; 643 browser_.reset(new Browser(create_params)); 644 } 645 646 private: 647 scoped_ptr<Browser> browser_; 648 scoped_ptr<aura::Window> native_window_; 649 650 DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura); 651 }; 652 653 // Creates a test browser window which has a native window. 654 scoped_ptr<TestBrowserWindowAura> CreateTestBrowserWindow( 655 const Browser::CreateParams& params) { 656 // Create a window. 657 aura::Window* window = new aura::Window(NULL); 658 window->set_id(0); 659 window->SetType(ui::wm::WINDOW_TYPE_NORMAL); 660 window->Init(aura::WINDOW_LAYER_TEXTURED); 661 window->Show(); 662 663 scoped_ptr<TestBrowserWindowAura> browser_window( 664 new TestBrowserWindowAura(window)); 665 browser_window->CreateBrowser(params); 666 return browser_window.Pass(); 667 } 668 669 // Watches WebContents and blocks until it is destroyed. This is needed for 670 // the destruction of a V2 application. 671 class WebContentsDestroyedWatcher : public content::WebContentsObserver { 672 public: 673 explicit WebContentsDestroyedWatcher(content::WebContents* web_contents) 674 : content::WebContentsObserver(web_contents), 675 message_loop_runner_(new content::MessageLoopRunner) { 676 EXPECT_TRUE(web_contents != NULL); 677 } 678 virtual ~WebContentsDestroyedWatcher() {} 679 680 // Waits until the WebContents is destroyed. 681 void Wait() { 682 message_loop_runner_->Run(); 683 } 684 685 private: 686 // Overridden WebContentsObserver methods. 687 virtual void WebContentsDestroyed() OVERRIDE { 688 message_loop_runner_->Quit(); 689 } 690 691 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 692 693 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedWatcher); 694 }; 695 696 // A V1 windowed application. 697 class V1App : public TestBrowserWindow { 698 public: 699 V1App(Profile* profile, const std::string& app_name) { 700 // Create a window. 701 native_window_.reset(new aura::Window(NULL)); 702 native_window_->set_id(0); 703 native_window_->SetType(ui::wm::WINDOW_TYPE_POPUP); 704 native_window_->Init(aura::WINDOW_LAYER_TEXTURED); 705 native_window_->Show(); 706 aura::client::ParentWindowWithContext(native_window_.get(), 707 ash::Shell::GetPrimaryRootWindow(), 708 gfx::Rect(10, 10, 20, 30)); 709 Browser::CreateParams params = 710 Browser::CreateParams::CreateForApp(kCrxAppPrefix + app_name, 711 true /* trusted_source */, 712 gfx::Rect(), 713 profile, 714 chrome::HOST_DESKTOP_TYPE_ASH); 715 params.window = this; 716 browser_.reset(new Browser(params)); 717 chrome::AddTabAt(browser_.get(), GURL(), 0, true); 718 } 719 720 virtual ~V1App() { 721 // close all tabs. Note that we do not need to destroy the browser itself. 722 browser_->tab_strip_model()->CloseAllTabs(); 723 } 724 725 Browser* browser() { return browser_.get(); } 726 727 // TestBrowserWindow override: 728 virtual gfx::NativeWindow GetNativeWindow() OVERRIDE { 729 return native_window_.get(); 730 } 731 732 private: 733 // The associated browser with this app. 734 scoped_ptr<Browser> browser_; 735 736 // The native window we use. 737 scoped_ptr<aura::Window> native_window_; 738 739 DISALLOW_COPY_AND_ASSIGN(V1App); 740 }; 741 742 // A V2 application which gets created with an |extension| and for a |profile|. 743 // Upon destruction it will properly close the application. 744 class V2App { 745 public: 746 V2App(Profile* profile, const extensions::Extension* extension) { 747 window_ = 748 new apps::AppWindow(profile, new ChromeAppWindowDelegate(), extension); 749 apps::AppWindow::CreateParams params = apps::AppWindow::CreateParams(); 750 window_->Init( 751 GURL(std::string()), new apps::AppWindowContentsImpl(window_), params); 752 } 753 754 virtual ~V2App() { 755 WebContentsDestroyedWatcher destroyed_watcher(window_->web_contents()); 756 window_->GetBaseWindow()->Close(); 757 destroyed_watcher.Wait(); 758 } 759 760 apps::AppWindow* window() { return window_; } 761 762 private: 763 // The app window which represents the application. Note that the window 764 // deletes itself asynchronously after window_->GetBaseWindow()->Close() gets 765 // called. 766 apps::AppWindow* window_; 767 768 DISALLOW_COPY_AND_ASSIGN(V2App); 769 }; 770 771 // The testing framework to test multi profile scenarios. 772 class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest 773 : public ChromeLauncherControllerTest { 774 protected: 775 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() { 776 } 777 778 virtual ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() { 779 } 780 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())); 785 786 ASSERT_TRUE(profile_manager_->SetUp()); 787 788 // AvatarMenu and multiple profiles works after user logged in. 789 profile_manager_->SetLoggedIn(true); 790 791 // Initialize the UserManager singleton to a fresh FakeUserManager instance. 792 user_manager_enabler_.reset( 793 new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager)); 794 795 // Initialize the rest. 796 ChromeLauncherControllerTest::SetUp(); 797 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); 803 } 804 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); 811 812 // A Task is leaked if we don't destroy everything, then run the message 813 // loop. 814 base::MessageLoop::current()->PostTask(FROM_HERE, 815 base::MessageLoop::QuitClosure()); 816 base::MessageLoop::current()->Run(); 817 } 818 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); 829 830 GetFakeUserManager()->UserLoggedIn( 831 email_string, 832 email_string + kUserIdHashSuffix, 833 false); 834 835 std::string profile_name = 836 chrome::kProfileDirPrefix + email_string + kUserIdHashSuffix; 837 TestingProfile* profile = profile_manager()->CreateTestingProfile( 838 profile_name, 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); 850 return profile; 851 } 852 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); 867 } 868 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); 876 877 BrowserList::SetLastActive(browser); 878 NavigateAndCommitActiveTabWithTitle( 879 browser, GURL(url), ASCIIToUTF16(title)); 880 return browser; 881 } 882 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), 897 app_name); 898 SetAppTabHelper(app_tab_helper); 899 900 NavigateAndCommitActiveTabWithTitle( 901 v1_app->browser(), GURL(url), ASCIIToUTF16("")); 902 return v1_app; 903 } 904 905 ash::test::TestSessionStateDelegate* session_delegate() { 906 return static_cast<ash::test::TestSessionStateDelegate*>( 907 ash::Shell::GetInstance()->session_state_delegate()); 908 } 909 ash::test::TestShellDelegate* shell_delegate() { return shell_delegate_; } 910 911 // Override BrowserWithTestWindowTest: 912 virtual TestingProfile* CreateProfile() OVERRIDE { 913 return CreateMultiUserProfile("user1"); 914 } 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); 921 } 922 923 private: 924 typedef std::map<Profile*, std::string> ProfileToNameMap; 925 TestingProfileManager* profile_manager() { return profile_manager_.get(); } 926 927 chromeos::FakeUserManager* GetFakeUserManager() { 928 return static_cast<chromeos::FakeUserManager*>( 929 chromeos::UserManager::Get()); 930 } 931 932 scoped_ptr<TestingProfileManager> profile_manager_; 933 scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; 934 935 ash::test::TestShellDelegate* shell_delegate_; 936 937 ProfileToNameMap created_profiles_; 938 939 DISALLOW_COPY_AND_ASSIGN( 940 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest); 941 }; 942 #endif // defined(OS_CHROMEOS) 943 944 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())); 952 953 // Installing |extension3_| should add it to the launcher - behind the 954 // chrome icon. 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())); 959 } 960 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 963 // order. 964 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsReverseOrder) { 965 InitLauncherController(); 966 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()); 979 980 // Installing |extension3_| should add it to the shelf - behind the 981 // chrome icon. 982 ash::ShelfItem item; 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()); 987 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()); 993 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()); 998 } 999 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 1002 // order. 1003 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrder) { 1004 InitLauncherController(); 1005 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()); 1018 1019 // Installing |extension2_| should add it to the launcher - behind the 1020 // chrome icon. 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()); 1025 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()); 1031 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()); 1036 } 1037 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(); 1043 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()); 1056 1057 // Installing |extension2_| should add it to the shelf - behind the 1058 // chrome icon. 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()); 1064 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()); 1070 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()); 1075 } 1076 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()); 1094 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()); 1112 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()); 1122 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()); 1127 1128 extension_service_->UnloadExtension(extension2_->id(), 1129 UnloadedExtensionInfo::REASON_UNINSTALL); 1130 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus()); 1131 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()); 1136 } 1137 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())); 1144 EXPECT_FALSE( 1145 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1146 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); 1147 EXPECT_FALSE( 1148 launcher_controller_->IsWindowedAppInLauncher(extension2_->id())); 1149 1150 launcher_controller_->LockV1AppWithID(extension1_->id()); 1151 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())); 1157 EXPECT_FALSE( 1158 launcher_controller_->IsWindowedAppInLauncher(extension2_->id())); 1159 1160 launcher_controller_->UnlockV1AppWithID(extension1_->id()); 1161 1162 EXPECT_EQ(2, model_->item_count()); 1163 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); 1164 EXPECT_FALSE( 1165 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1166 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); 1167 EXPECT_FALSE( 1168 launcher_controller_->IsWindowedAppInLauncher(extension2_->id())); 1169 } 1170 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())); 1177 EXPECT_FALSE( 1178 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1179 1180 for (int i = 0; i < 2; i++) { 1181 launcher_controller_->LockV1AppWithID(extension1_->id()); 1182 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())); 1188 } 1189 1190 launcher_controller_->UnlockV1AppWithID(extension1_->id()); 1191 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())); 1196 1197 launcher_controller_->UnlockV1AppWithID(extension1_->id()); 1198 1199 EXPECT_EQ(2, model_->item_count()); 1200 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); 1201 EXPECT_FALSE( 1202 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1203 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); 1204 EXPECT_FALSE( 1205 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1206 } 1207 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())); 1214 EXPECT_FALSE( 1215 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1216 1217 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); 1218 launcher_controller_->PinAppWithID(extension1_->id()); 1219 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); 1220 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())); 1224 EXPECT_FALSE( 1225 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1226 1227 launcher_controller_->LockV1AppWithID(extension1_->id()); 1228 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())); 1232 EXPECT_FALSE( 1233 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1234 1235 launcher_controller_->UnlockV1AppWithID(extension1_->id()); 1236 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())); 1240 EXPECT_FALSE( 1241 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1242 1243 launcher_controller_->UnpinAppWithID(extension1_->id()); 1244 1245 EXPECT_EQ(2, model_->item_count()); 1246 } 1247 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())); 1254 EXPECT_FALSE( 1255 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1256 1257 launcher_controller_->PinAppWithID(extension1_->id()); 1258 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())); 1262 EXPECT_FALSE( 1263 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1264 1265 launcher_controller_->LockV1AppWithID(extension1_->id()); 1266 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())); 1270 EXPECT_FALSE( 1271 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1272 1273 launcher_controller_->UnpinAppWithID(extension1_->id()); 1274 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())); 1279 1280 launcher_controller_->UnlockV1AppWithID(extension1_->id()); 1281 1282 EXPECT_EQ(2, model_->item_count()); 1283 } 1284 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()); 1292 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 1299 // running type. 1300 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus()); 1301 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(); 1306 1307 // Switch some items and check that restoring a user which was not yet 1308 // remembered changes nothing. 1309 model_->Move(2, 3); 1310 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus()); 1311 RestoreUnpinnedRunningApplicationOrder("second-fake-user (at) fake.com"); 1312 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus()); 1313 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()); 1317 1318 // Switch again some items and even delete one - making sure that the missing 1319 // item gets properly handled. 1320 model_->Move(3, 4); 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()); 1325 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()); 1333 } 1334 1335 // Check that with multi profile V1 apps are properly added / removed from the 1336 // shelf. 1337 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, 1338 V1AppUpdateOnUserSwitch) { 1339 // Create a browser item in the LauncherController. 1340 InitLauncherController(); 1341 EXPECT_EQ(2, model_->item_count()); 1342 { 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()); 1347 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()); 1353 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. 1358 } 1359 EXPECT_EQ(2, model_->item_count()); 1360 } 1361 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(); 1367 1368 // First test: Create an app when the user is not active. 1369 std::string user2 = "user2"; 1370 TestingProfile* profile2 = CreateMultiUserProfile(user2); 1371 { 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()); 1376 1377 // However - switching to the user should show it. 1378 SwitchActiveUser(profile2->GetProfileName()); 1379 EXPECT_EQ(3, model_->item_count()); 1380 1381 // Second test: Remove the app when the user is not active and see that it 1382 // works. 1383 SwitchActiveUser(profile()->GetProfileName()); 1384 EXPECT_EQ(2, model_->item_count()); 1385 // Note: the closure ends and the browser will go away. 1386 } 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()); 1392 } 1393 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(); 1399 1400 chrome::MultiUserWindowManager* manager = 1401 chrome::MultiUserWindowManager::GetInstance(); 1402 1403 // First create an app when the user is active. 1404 std::string user2 = "user2"; 1405 TestingProfile* profile2 = CreateMultiUserProfile(user2); 1406 { 1407 // Create a "windowed gmail app". 1408 scoped_ptr<V1App> v1_app(CreateRunningV1App( 1409 profile(), 1410 extension_misc::kGmailAppId, 1411 kGmailLaunchURL)); 1412 EXPECT_EQ(3, model_->item_count()); 1413 1414 // Transfer the app to the other screen and switch users. 1415 manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(), 1416 user2); 1417 EXPECT_EQ(3, model_->item_count()); 1418 SwitchActiveUser(profile2->GetProfileName()); 1419 EXPECT_EQ(2, model_->item_count()); 1420 } 1421 // After the app was destroyed, switch back. (which caused already a crash). 1422 SwitchActiveUser(profile()->GetProfileName()); 1423 1424 // Create the same app again - which was also causing the crash. 1425 EXPECT_EQ(2, model_->item_count()); 1426 { 1427 // Create a "windowed gmail app". 1428 scoped_ptr<V1App> v1_app(CreateRunningV1App( 1429 profile(), 1430 extension_misc::kGmailAppId, 1431 kGmailLaunchURL)); 1432 EXPECT_EQ(3, model_->item_count()); 1433 } 1434 SwitchActiveUser(profile2->GetProfileName()); 1435 EXPECT_EQ(2, model_->item_count()); 1436 } 1437 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); 1445 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()); 1450 { 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()); 1455 1456 // However - switching to the user should show it. 1457 SwitchActiveUser(profile()->GetProfileName()); 1458 EXPECT_EQ(3, model_->item_count()); 1459 1460 // Second test: Remove the app when the user is not active and see that it 1461 // works. 1462 SwitchActiveUser(profile2->GetProfileName()); 1463 EXPECT_EQ(2, model_->item_count()); 1464 v1_app.reset(); 1465 } 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()); 1471 } 1472 1473 // Check that activating an item which is on another user's desktop, will bring 1474 // it back. 1475 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, 1476 TestLauncherActivationPullsBackWindow) { 1477 // Create a browser item in the LauncherController. 1478 InitLauncherController(); 1479 chrome::MultiUserWindowManager* manager = 1480 chrome::MultiUserWindowManager::GetInstance(); 1481 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()); 1489 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); 1495 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(), 1499 false); 1500 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user)); 1501 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(), 1507 false); 1508 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user)); 1509 } 1510 #endif 1511 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())); 1518 EXPECT_FALSE( 1519 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1520 1521 launcher_controller_->LockV1AppWithID(extension1_->id()); 1522 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())); 1527 1528 launcher_controller_->PinAppWithID(extension1_->id()); 1529 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())); 1533 EXPECT_FALSE( 1534 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1535 1536 launcher_controller_->UnlockV1AppWithID(extension1_->id()); 1537 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())); 1541 EXPECT_FALSE( 1542 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); 1543 1544 launcher_controller_->UnpinAppWithID(extension1_->id()); 1545 1546 EXPECT_EQ(2, model_->item_count()); 1547 } 1548 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 / 1551 // policy change. 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()); 1571 1572 // Now request to pin all items which should convert the locked item into a 1573 // pinned item. 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()); 1581 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()); 1593 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()); 1600 } 1601 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 / 1604 // policy change. 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()); 1625 1626 // Now request to pin all items which should convert the locked item into a 1627 // pinned item. 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()); 1635 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()); 1645 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()); 1652 } 1653 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); 1660 // Show user 1. 1661 SetShelfChromeIconIndex(6); 1662 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1663 user_a.DeepCopy()); 1664 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", 1665 GetPinnedAppStatus()); 1666 1667 // Show user 2. 1668 SetShelfChromeIconIndex(4); 1669 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1670 user_b.DeepCopy()); 1671 1672 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus()); 1673 1674 // Switch back to 1. 1675 SetShelfChromeIconIndex(8); 1676 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1677 user_a.DeepCopy()); 1678 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", 1679 GetPinnedAppStatus()); 1680 1681 // Switch back to 2. 1682 SetShelfChromeIconIndex(4); 1683 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1684 user_b.DeepCopy()); 1685 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus()); 1686 } 1687 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); 1695 1696 // Run App1 and assume that it is a V2 app. 1697 CreateRunningV2App(extension1_->id()); 1698 1699 // Show user 1. 1700 SetShelfChromeIconIndex(6); 1701 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1702 user_a.DeepCopy()); 1703 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", 1704 GetPinnedAppStatus()); 1705 1706 // Show user 2. 1707 SetShelfChromeIconIndex(4); 1708 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1709 user_b.DeepCopy()); 1710 1711 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus()); 1712 1713 // Switch back to 1. 1714 SetShelfChromeIconIndex(8); 1715 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1716 user_a.DeepCopy()); 1717 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", 1718 GetPinnedAppStatus()); 1719 1720 // Switch back to 2. 1721 SetShelfChromeIconIndex(4); 1722 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1723 user_b.DeepCopy()); 1724 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus()); 1725 } 1726 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); 1736 1737 // Run App1 and assume that it is a V2 app. 1738 CreateRunningV2App(extension1_->id()); 1739 1740 // Show user 1. 1741 SetShelfChromeIconIndex(5); 1742 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1743 user_a.DeepCopy()); 1744 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6", 1745 GetPinnedAppStatus()); 1746 1747 // Show user 2. 1748 SetShelfChromeIconIndex(4); 1749 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1750 user_b.DeepCopy()); 1751 1752 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus()); 1753 1754 // Switch back to 1. 1755 SetShelfChromeIconIndex(5); 1756 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, 1757 user_a.DeepCopy()); 1758 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6", 1759 GetPinnedAppStatus()); 1760 } 1761 1762 TEST_F(ChromeLauncherControllerTest, Policy) { 1763 extension_service_->AddExtension(extension1_.get()); 1764 extension_service_->AddExtension(extension3_.get()); 1765 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()); 1771 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())); 1781 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())); 1790 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())); 1800 } 1801 1802 TEST_F(ChromeLauncherControllerTest, UnpinWithUninstall) { 1803 extension_service_->AddExtension(extension3_.get()); 1804 extension_service_->AddExtension(extension4_.get()); 1805 1806 InitLauncherController(); 1807 1808 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); 1809 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); 1810 1811 extension_service_->UnloadExtension(extension3_->id(), 1812 UnloadedExtensionInfo::REASON_UNINSTALL); 1813 1814 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); 1815 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); 1816 } 1817 1818 TEST_F(ChromeLauncherControllerTest, PrefUpdates) { 1819 extension_service_->AddExtension(extension2_.get()); 1820 extension_service_->AddExtension(extension3_.get()); 1821 extension_service_->AddExtension(extension4_.get()); 1822 1823 InitLauncherController(); 1824 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); 1832 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); 1843 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); 1853 1854 // Order changes are reflected correctly. 1855 pref_value.Clear(); 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); 1864 1865 // Clearing works. 1866 pref_value.Clear(); 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); 1872 } 1873 1874 TEST_F(ChromeLauncherControllerTest, PendingInsertionOrder) { 1875 extension_service_->AddExtension(extension1_.get()); 1876 extension_service_->AddExtension(extension3_.get()); 1877 1878 InitLauncherController(); 1879 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()); 1886 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; 1891 1892 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); 1893 EXPECT_EQ(expected_launchers, actual_launchers); 1894 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); 1900 } 1901 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[], 1911 bool is_browser) { 1912 ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0); 1913 // A new behavior has been added: Only show menus if there is at least one 1914 // item available. 1915 if (expected_items < 1 && is_browser) { 1916 EXPECT_EQ(0u, items.size()); 1917 return items.size() == 0; 1918 } 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. 1925 if (i == 1) 1926 EXPECT_TRUE(items[i]->HasLeadingSeparator()); 1927 else 1928 EXPECT_FALSE(items[i]->HasLeadingSeparator()); 1929 } 1930 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)); 1944 } 1945 return items.size() == expected_items + 1; 1946 } 1947 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()); 1952 1953 InitLauncherController(); 1954 1955 // Check that the browser list is empty at this time. 1956 ash::ShelfItem item_browser; 1957 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; 1958 item_browser.id = 1959 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); 1960 EXPECT_TRUE(CheckMenuCreation( 1961 launcher_controller_.get(), item_browser, 0, NULL, true)); 1962 1963 // Now make the created browser() visible by adding it to the active browser 1964 // list. 1965 BrowserList::SetLastActive(browser()); 1966 base::string16 title1 = ASCIIToUTF16("Test1"); 1967 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1); 1968 base::string16 one_menu_item[] = { title1 }; 1969 1970 EXPECT_TRUE(CheckMenuCreation( 1971 launcher_controller_.get(), item_browser, 1, one_menu_item, true)); 1972 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"), 1981 title2); 1982 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)); 1988 1989 // Apparently we have to close all tabs we have. 1990 chrome::CloseTab(browser2.get()); 1991 } 1992 1993 #if defined(OS_CHROMEOS) 1994 // Check the multi profile case where only user related browsers should show 1995 // up. 1996 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, 1997 BrowserMenuGenerationTwoUsers) { 1998 // Create a browser item in the LauncherController. 1999 InitLauncherController(); 2000 2001 ash::ShelfItem item_browser; 2002 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; 2003 item_browser.id = 2004 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); 2005 2006 // Check that the menu is empty. 2007 chrome::NewTab(browser()); 2008 EXPECT_TRUE(CheckMenuCreation( 2009 launcher_controller_.get(), item_browser, 0, NULL, true)); 2010 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)); 2018 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)); 2028 2029 // Switch to the other user and make sure that only that browser window gets 2030 // shown. 2031 SwitchActiveUser(profile2->GetProfileName()); 2032 EXPECT_TRUE(CheckMenuCreation( 2033 launcher_controller_.get(), item_browser, 1, one_menu_item2, true)); 2034 2035 // Transferred browsers of other users should not show up in the list. 2036 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( 2037 browser()->window()->GetNativeWindow(), 2038 user2); 2039 EXPECT_TRUE(CheckMenuCreation( 2040 launcher_controller_.get(), item_browser, 1, one_menu_item2, true)); 2041 2042 chrome::CloseTab(browser2.get()); 2043 } 2044 #endif // defined(OS_CHROMEOS) 2045 2046 // Check that V1 apps are correctly reflected in the launcher menu using the 2047 // refocus logic. 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()); 2053 2054 InitLauncherControllerWithBrowser(); 2055 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())); 2059 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)); 2068 2069 // Check the menu content. 2070 ash::ShelfItem item_browser; 2071 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; 2072 item_browser.id = 2073 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); 2074 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)); 2080 2081 // Set the gmail URL to a new tab. 2082 base::string16 title1 = ASCIIToUTF16("Test1"); 2083 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); 2084 2085 base::string16 one_menu_item[] = { title1 }; 2086 EXPECT_TRUE(CheckMenuCreation( 2087 launcher_controller_.get(), item_gmail, 1, one_menu_item, false)); 2088 2089 // Create one empty tab. 2090 chrome::NewTab(browser()); 2091 base::string16 title2 = ASCIIToUTF16("Test2"); 2092 NavigateAndCommitActiveTabWithTitle( 2093 browser(), 2094 GURL("https://bla"), 2095 title2); 2096 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)); 2104 2105 // Even though the item is in the V1 app list, it should also be in the 2106 // browser list. 2107 base::string16 browser_menu_item[] = {title3}; 2108 EXPECT_TRUE(CheckMenuCreation( 2109 launcher_controller_.get(), item_browser, 1, browser_menu_item, false)); 2110 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); 2114 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)); 2120 } 2121 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()); 2129 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)); 2138 2139 // Check the menu content. 2140 ash::ShelfItem item_browser; 2141 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; 2142 item_browser.id = 2143 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); 2144 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)); 2150 2151 // Set the gmail URL to a new tab. 2152 base::string16 title1 = ASCIIToUTF16("Test1"); 2153 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); 2154 2155 base::string16 one_menu_item[] = { title1 }; 2156 EXPECT_TRUE(CheckMenuCreation( 2157 launcher_controller_.get(), item_gmail, 1, one_menu_item, false)); 2158 2159 // Create a second profile and switch to that user. 2160 std::string user2 = "user2"; 2161 TestingProfile* profile2 = CreateMultiUserProfile(user2); 2162 SwitchActiveUser(profile2->GetProfileName()); 2163 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)); 2169 2170 // Transfer the browser of the first user - it should still not show up. 2171 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( 2172 browser()->window()->GetNativeWindow(), 2173 user2); 2174 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)); 2179 } 2180 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()); 2190 2191 // Add a v2 app. 2192 V2App v2_app(profile(), extension1_); 2193 EXPECT_EQ(3, model_->item_count()); 2194 2195 // After switching users the item should go away. 2196 SwitchActiveUser(profile2->GetProfileName()); 2197 EXPECT_EQ(2, model_->item_count()); 2198 2199 // And it should come back when switching back. 2200 SwitchActiveUser(profile()->GetProfileName()); 2201 EXPECT_EQ(3, model_->item_count()); 2202 } 2203 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 2206 // deletes the app. 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()); 2214 2215 // Switch to an inactive user. 2216 SwitchActiveUser(profile2->GetProfileName()); 2217 EXPECT_EQ(2, model_->item_count()); 2218 2219 // Add the v2 app to the inactive user and check that no item was added to 2220 // the launcher. 2221 { 2222 V2App v2_app(profile(), extension1_); 2223 EXPECT_EQ(2, model_->item_count()); 2224 2225 // Switch to the primary user and check that the item is shown. 2226 SwitchActiveUser(profile()->GetProfileName()); 2227 EXPECT_EQ(3, model_->item_count()); 2228 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()); 2233 } 2234 2235 // After the application was killed there should be still 2 items. 2236 EXPECT_EQ(2, model_->item_count()); 2237 2238 // Switching then back to the default user should not show the additional item 2239 // anymore. 2240 SwitchActiveUser(profile()->GetProfileName()); 2241 EXPECT_EQ(2, model_->item_count()); 2242 } 2243 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(); 2251 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()); 2257 2258 // A v2 app for user #1 should be shown first and get hidden when switching to 2259 // desktop #2. 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()); 2264 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()); 2269 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()); 2275 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()); 2282 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()); 2291 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()); 2299 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()); 2308 } 2309 2310 // Check that V2 applications hide correctly on the shelf when the app window 2311 // is hidden. 2312 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, 2313 V2AppHiddenWindows) { 2314 InitLauncherController(); 2315 2316 TestingProfile* profile2 = CreateMultiUserProfile("user-2"); 2317 SwitchActiveUser(profile()->GetProfileName()); 2318 EXPECT_EQ(2, model_->item_count()); 2319 2320 V2App v2_app_1(profile(), extension1_); 2321 EXPECT_EQ(3, model_->item_count()); 2322 { 2323 // Hide and show the app. 2324 v2_app_1.window()->Hide(); 2325 EXPECT_EQ(2, model_->item_count()); 2326 2327 v2_app_1.window()->Show(apps::AppWindow::SHOW_ACTIVE); 2328 EXPECT_EQ(3, model_->item_count()); 2329 } 2330 { 2331 // Switch user, hide and show the app and switch back. 2332 SwitchActiveUser(profile2->GetProfileName()); 2333 EXPECT_EQ(2, model_->item_count()); 2334 2335 v2_app_1.window()->Hide(); 2336 EXPECT_EQ(2, model_->item_count()); 2337 2338 v2_app_1.window()->Show(apps::AppWindow::SHOW_ACTIVE); 2339 EXPECT_EQ(2, model_->item_count()); 2340 2341 SwitchActiveUser(profile()->GetProfileName()); 2342 EXPECT_EQ(3, model_->item_count()); 2343 } 2344 { 2345 // Switch user, hide the app, switch back and then show it again. 2346 SwitchActiveUser(profile2->GetProfileName()); 2347 EXPECT_EQ(2, model_->item_count()); 2348 2349 v2_app_1.window()->Hide(); 2350 EXPECT_EQ(2, model_->item_count()); 2351 2352 SwitchActiveUser(profile()->GetProfileName()); 2353 EXPECT_EQ(2, model_->item_count()); 2354 2355 v2_app_1.window()->Show(apps::AppWindow::SHOW_ACTIVE); 2356 EXPECT_EQ(3, model_->item_count()); 2357 } 2358 { 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()); 2362 2363 v2_app_2.window()->Hide(); 2364 EXPECT_EQ(3, model_->item_count()); 2365 2366 v2_app_2.window()->Show(apps::AppWindow::SHOW_ACTIVE); 2367 EXPECT_EQ(3, model_->item_count()); 2368 2369 v2_app_1.window()->Hide(); 2370 v2_app_2.window()->Hide(); 2371 EXPECT_EQ(2, model_->item_count()); 2372 } 2373 } 2374 #endif // defined(OS_CHROMEOS) 2375 2376 // Checks that the generated menu list properly activates items. 2377 TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) { 2378 InitLauncherControllerWithBrowser(); 2379 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); 2390 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). 2401 { 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. 2407 int first_item = 2408 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0; 2409 menu->ActivatedAt(first_item + 3); 2410 } 2411 EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); 2412 2413 // Execute the first item. 2414 { 2415 scoped_ptr<ash::ShelfMenuModel> menu(new LauncherApplicationMenuItemModel( 2416 launcher_controller_->GetApplicationList(item_gmail, 0))); 2417 int first_item = 2418 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0; 2419 menu->ActivatedAt(first_item + 2); 2420 } 2421 // Now the active tab should be the second item. 2422 EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); 2423 } 2424 2425 // Checks that the generated menu list properly deletes items. 2426 TEST_F(ChromeLauncherControllerTest, V1AppMenuDeletionExecution) { 2427 InitLauncherControllerWithBrowser(); 2428 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); 2439 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)); 2447 2448 int tabs = browser()->tab_strip_model()->count(); 2449 // Activate the proper tab through the menu item. 2450 { 2451 ChromeLauncherAppMenuItems items = 2452 launcher_controller_->GetApplicationList(item_gmail, 0); 2453 items[1]->Execute(0); 2454 EXPECT_EQ(tabs, browser()->tab_strip_model()->count()); 2455 } 2456 2457 // Delete one tab through the menu item. 2458 { 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()); 2463 } 2464 } 2465 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()); 2471 2472 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl(); 2473 SetAppIconLoader(app_icon_loader); 2474 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, 2480 "id", 2481 app_id, 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(); 2490 2491 // App panels should have a separate identifier than the app id 2492 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(app_id)); 2493 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(); 2500 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, 2506 "id", 2507 app_id, 2508 launcher_controller_.get()); 2509 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(); 2515 2516 launcher_controller_->CloseLauncherItem(shelf_id2); 2517 launcher_controller_->CloseLauncherItem(shelf_id1); 2518 EXPECT_EQ(2, model_observer_->removed()); 2519 } 2520 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(); 2525 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(); 2532 2533 // Check that the launcher controller does not recognize the running app. 2534 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content)); 2535 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())); 2543 2544 // Check that it is now handled. 2545 EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content)); 2546 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()); 2552 } 2553 2554 // Tests that the Gmail extension does not match the offline verison. 2555 TEST_F(ChromeLauncherControllerTest, GmailOfflineMatching) { 2556 InitLauncherControllerWithBrowser(); 2557 2558 // Create a Gmail browser tab. 2559 chrome::NewTab(browser()); 2560 base::string16 title = ASCIIToUTF16("Test"); 2561 NavigateAndCommitActiveTabWithTitle(browser(), 2562 GURL(offline_gmail_url), 2563 title); 2564 content::WebContents* content = 2565 browser()->tab_strip_model()->GetActiveWebContents(); 2566 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())); 2574 2575 // The content should not be able to be handled by the app. 2576 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content)); 2577 } 2578 2579 // Verify that the launcher item positions are persisted and restored. 2580 TEST_F(ChromeLauncherControllerTest, PersistLauncherItemPositions) { 2581 InitLauncherController(); 2582 2583 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl; 2584 SetAppTabHelper(app_tab_helper); 2585 2586 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type); 2587 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type); 2588 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"); 2596 2597 EXPECT_FALSE(launcher_controller_->IsAppPinned("1")); 2598 launcher_controller_->PinAppWithID("1"); 2599 EXPECT_TRUE(launcher_controller_->IsAppPinned("1")); 2600 launcher_controller_->PinAppWithID("2"); 2601 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); 2606 2607 // Move browser shortcut item from index 1 to index 3. 2608 model_->Move(1, 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); 2613 2614 launcher_controller_.reset(); 2615 if (!ash::Shell::HasInstance()) { 2616 delete item_delegate_manager_; 2617 } else { 2618 // Clear already registered ShelfItemDelegate. 2619 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_); 2620 test.RemoveAllShelfItemDelegateForTest(); 2621 } 2622 model_.reset(new ash::ShelfModel); 2623 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_); 2634 } 2635 launcher_controller_->Init(); 2636 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); 2642 } 2643 2644 // Verifies pinned apps are persisted and restored. 2645 TEST_F(ChromeLauncherControllerTest, PersistPinned) { 2646 InitLauncherControllerWithBrowser(); 2647 size_t initial_size = model_->items().size(); 2648 2649 TabStripModel* tab_strip_model = browser()->tab_strip_model(); 2650 EXPECT_EQ(1, tab_strip_model->count()); 2651 2652 TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl; 2653 app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1"); 2654 SetAppTabHelper(app_tab_helper); 2655 2656 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl; 2657 SetAppIconLoader(app_icon_loader); 2658 EXPECT_EQ(0, app_icon_loader->fetch_count()); 2659 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()); 2668 2669 launcher_controller_.reset(); 2670 if (!ash::Shell::HasInstance()) { 2671 delete item_delegate_manager_; 2672 } else { 2673 // Clear already registered ShelfItemDelegate. 2674 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_); 2675 test.RemoveAllShelfItemDelegateForTest(); 2676 } 2677 model_.reset(new ash::ShelfModel); 2678 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_); 2690 } 2691 launcher_controller_->Init(); 2692 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); 2698 2699 launcher_controller_->UnpinAppWithID("1"); 2700 ASSERT_EQ(initial_size, model_->items().size()); 2701 } 2702