| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <memory> | |
| 11 #include <set> | |
| 12 #include <string> | |
| 13 #include <utility> | |
| 14 #include <vector> | |
| 15 | |
| 16 #include "ash/ash_switches.h" | |
| 17 #include "ash/common/shelf/shelf_item_delegate_manager.h" | |
| 18 #include "ash/common/shelf/shelf_model.h" | |
| 19 #include "ash/common/shelf/shelf_model_observer.h" | |
| 20 #include "ash/shell.h" | |
| 21 #include "ash/test/shelf_item_delegate_manager_test_api.h" | |
| 22 #include "ash/test/test_session_state_delegate.h" | |
| 23 #include "ash/test/test_shell_delegate.h" | |
| 24 #include "base/command_line.h" | |
| 25 #include "base/compiler_specific.h" | |
| 26 #include "base/files/file_path.h" | |
| 27 #include "base/location.h" | |
| 28 #include "base/macros.h" | |
| 29 #include "base/memory/ptr_util.h" | |
| 30 #include "base/message_loop/message_loop.h" | |
| 31 #include "base/single_thread_task_runner.h" | |
| 32 #include "base/strings/utf_string_conversions.h" | |
| 33 #include "base/threading/thread_task_runner_handle.h" | |
| 34 #include "base/values.h" | |
| 35 #include "build/build_config.h" | |
| 36 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" | |
| 37 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" | |
| 38 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" | |
| 39 #include "chrome/browser/extensions/extension_service.h" | |
| 40 #include "chrome/browser/extensions/test_extension_system.h" | |
| 41 #include "chrome/browser/lifetime/scoped_keep_alive.h" | |
| 42 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" | |
| 43 #include "chrome/browser/ui/app_list/arc/arc_app_test.h" | |
| 44 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" | |
| 45 #include "chrome/browser/ui/apps/chrome_app_delegate.h" | |
| 46 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" | |
| 47 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h" | |
| 48 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h" | |
| 49 #include "chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_cont
roller.h" | |
| 50 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" | |
| 51 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h" | |
| 52 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" | |
| 53 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" | |
| 54 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" | |
| 55 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h" | |
| 56 #include "chrome/browser/ui/browser.h" | |
| 57 #include "chrome/browser/ui/browser_commands.h" | |
| 58 #include "chrome/browser/ui/browser_finder.h" | |
| 59 #include "chrome/browser/ui/browser_list.h" | |
| 60 #include "chrome/browser/ui/browser_tabstrip.h" | |
| 61 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 62 #include "chrome/common/chrome_constants.h" | |
| 63 #include "chrome/common/chrome_switches.h" | |
| 64 #include "chrome/common/extensions/extension_constants.h" | |
| 65 #include "chrome/common/pref_names.h" | |
| 66 #include "chrome/test/base/browser_with_test_window_test.h" | |
| 67 #include "chrome/test/base/test_browser_window_aura.h" | |
| 68 #include "chrome/test/base/testing_browser_process.h" | |
| 69 #include "chrome/test/base/testing_profile.h" | |
| 70 #include "chrome/test/base/testing_profile_manager.h" | |
| 71 #include "chromeos/chromeos_switches.h" | |
| 72 #include "components/arc/common/app.mojom.h" | |
| 73 #include "components/arc/test/fake_app_instance.h" | |
| 74 #include "components/arc/test/fake_arc_bridge_service.h" | |
| 75 #include "components/exo/shell_surface.h" | |
| 76 #include "components/signin/core/account_id/account_id.h" | |
| 77 #include "components/syncable_prefs/testing_pref_service_syncable.h" | |
| 78 #include "components/user_manager/fake_user_manager.h" | |
| 79 #include "content/public/browser/web_contents.h" | |
| 80 #include "content/public/browser/web_contents_observer.h" | |
| 81 #include "content/public/test/test_utils.h" | |
| 82 #include "content/public/test/web_contents_tester.h" | |
| 83 #include "extensions/browser/app_window/app_window_contents.h" | |
| 84 #include "extensions/browser/app_window/app_window_registry.h" | |
| 85 #include "extensions/browser/app_window/native_app_window.h" | |
| 86 #include "extensions/common/extension.h" | |
| 87 #include "extensions/common/manifest_constants.h" | |
| 88 #include "testing/gtest/include/gtest/gtest.h" | |
| 89 #include "ui/aura/client/window_tree_client.h" | |
| 90 #include "ui/aura/window.h" | |
| 91 #include "ui/base/models/menu_model.h" | |
| 92 #include "ui/views/widget/widget.h" | |
| 93 | |
| 94 using base::ASCIIToUTF16; | |
| 95 using extensions::Extension; | |
| 96 using extensions::Manifest; | |
| 97 using extensions::UnloadedExtensionInfo; | |
| 98 | |
| 99 namespace { | |
| 100 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u"; | |
| 101 const char* gmail_url = "https://mail.google.com/mail/u"; | |
| 102 const char* kGmailLaunchURL = "https://mail.google.com/mail/ca"; | |
| 103 | |
| 104 // An extension prefix. | |
| 105 const char kCrxAppPrefix[] = "_crx_"; | |
| 106 | |
| 107 // ShelfModelObserver implementation that tracks what messages are invoked. | |
| 108 class TestShelfModelObserver : public ash::ShelfModelObserver { | |
| 109 public: | |
| 110 TestShelfModelObserver() | |
| 111 : added_(0), | |
| 112 removed_(0), | |
| 113 changed_(0) { | |
| 114 } | |
| 115 | |
| 116 ~TestShelfModelObserver() override {} | |
| 117 | |
| 118 // Overridden from ash::ShelfModelObserver: | |
| 119 void ShelfItemAdded(int index) override { | |
| 120 ++added_; | |
| 121 last_index_ = index; | |
| 122 } | |
| 123 | |
| 124 void ShelfItemRemoved(int index, ash::ShelfID id) override { | |
| 125 ++removed_; | |
| 126 last_index_ = index; | |
| 127 } | |
| 128 | |
| 129 void ShelfItemChanged(int index, const ash::ShelfItem& old_item) override { | |
| 130 ++changed_; | |
| 131 last_index_ = index; | |
| 132 } | |
| 133 | |
| 134 void ShelfItemMoved(int start_index, int target_index) override { | |
| 135 last_index_ = target_index; | |
| 136 } | |
| 137 | |
| 138 void clear_counts() { | |
| 139 added_ = 0; | |
| 140 removed_ = 0; | |
| 141 changed_ = 0; | |
| 142 last_index_ = 0; | |
| 143 } | |
| 144 | |
| 145 int added() const { return added_; } | |
| 146 int removed() const { return removed_; } | |
| 147 int changed() const { return changed_; } | |
| 148 int last_index() const { return last_index_; } | |
| 149 | |
| 150 private: | |
| 151 int added_; | |
| 152 int removed_; | |
| 153 int changed_; | |
| 154 int last_index_; | |
| 155 | |
| 156 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver); | |
| 157 }; | |
| 158 | |
| 159 // Test implementation of AppIconLoader. | |
| 160 class TestAppIconLoaderImpl : public AppIconLoader { | |
| 161 public: | |
| 162 TestAppIconLoaderImpl() = default; | |
| 163 ~TestAppIconLoaderImpl() override = default; | |
| 164 | |
| 165 void AddSupportedApp(const std::string& id) { supported_apps_.insert(id); } | |
| 166 | |
| 167 // AppIconLoader implementation: | |
| 168 bool CanLoadImageForApp(const std::string& id) override { | |
| 169 return supported_apps_.find(id) != supported_apps_.end(); | |
| 170 } | |
| 171 | |
| 172 void FetchImage(const std::string& id) override { ++fetch_count_; } | |
| 173 | |
| 174 void ClearImage(const std::string& id) override { ++clear_count_; } | |
| 175 | |
| 176 void UpdateImage(const std::string& id) override {} | |
| 177 | |
| 178 int fetch_count() const { return fetch_count_; } | |
| 179 int clear_count() const { return clear_count_; } | |
| 180 | |
| 181 private: | |
| 182 int fetch_count_ = 0; | |
| 183 int clear_count_ = 0; | |
| 184 std::set<std::string> supported_apps_; | |
| 185 | |
| 186 DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl); | |
| 187 }; | |
| 188 | |
| 189 // Test implementation of LauncherControllerHelper. | |
| 190 class TestLauncherControllerHelper : public LauncherControllerHelper { | |
| 191 public: | |
| 192 TestLauncherControllerHelper() : LauncherControllerHelper(nullptr) {} | |
| 193 ~TestLauncherControllerHelper() override {} | |
| 194 | |
| 195 // Sets the id for the specified tab. | |
| 196 void SetAppID(content::WebContents* tab, const std::string& id) { | |
| 197 tab_id_map_[tab] = id; | |
| 198 } | |
| 199 | |
| 200 // Returns true if there is an id registered for |tab|. | |
| 201 bool HasAppID(content::WebContents* tab) const { | |
| 202 return tab_id_map_.find(tab) != tab_id_map_.end(); | |
| 203 } | |
| 204 | |
| 205 // LauncherControllerHelper: | |
| 206 std::string GetAppID(content::WebContents* tab) override { | |
| 207 return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] : | |
| 208 std::string(); | |
| 209 } | |
| 210 | |
| 211 bool IsValidIDForCurrentUser(const std::string& id) const override { | |
| 212 for (TabToStringMap::const_iterator i = tab_id_map_.begin(); | |
| 213 i != tab_id_map_.end(); ++i) { | |
| 214 if (i->second == id) | |
| 215 return true; | |
| 216 } | |
| 217 return false; | |
| 218 } | |
| 219 | |
| 220 void SetCurrentUser(Profile* profile) override { | |
| 221 // We can ignore this for now. | |
| 222 } | |
| 223 | |
| 224 ArcAppListPrefs* GetArcAppListPrefs() const override { return nullptr; } | |
| 225 | |
| 226 private: | |
| 227 typedef std::map<content::WebContents*, std::string> TabToStringMap; | |
| 228 | |
| 229 TabToStringMap tab_id_map_; | |
| 230 | |
| 231 DISALLOW_COPY_AND_ASSIGN(TestLauncherControllerHelper); | |
| 232 }; | |
| 233 | |
| 234 // Test implementation of a V2 app launcher item controller. | |
| 235 class TestV2AppLauncherItemController : public LauncherItemController { | |
| 236 public: | |
| 237 TestV2AppLauncherItemController(const std::string& app_id, | |
| 238 ChromeLauncherController* controller) | |
| 239 : LauncherItemController(LauncherItemController::TYPE_APP, | |
| 240 app_id, | |
| 241 controller) { | |
| 242 } | |
| 243 | |
| 244 ~TestV2AppLauncherItemController() override {} | |
| 245 | |
| 246 // Override for LauncherItemController: | |
| 247 bool IsOpen() const override { return true; } | |
| 248 bool IsVisible() const override { return true; } | |
| 249 void Launch(ash::LaunchSource source, int event_flags) override {} | |
| 250 ash::ShelfItemDelegate::PerformedAction Activate( | |
| 251 ash::LaunchSource source) override { | |
| 252 return kExistingWindowActivated; | |
| 253 } | |
| 254 void Close() override {} | |
| 255 ash::ShelfItemDelegate::PerformedAction ItemSelected( | |
| 256 const ui::Event& event) override { | |
| 257 return kExistingWindowActivated; | |
| 258 } | |
| 259 base::string16 GetTitle() override { return base::string16(); } | |
| 260 ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override { | |
| 261 ChromeLauncherAppMenuItems items; | |
| 262 items.push_back( | |
| 263 new ChromeLauncherAppMenuItem(base::string16(), NULL, false)); | |
| 264 items.push_back( | |
| 265 new ChromeLauncherAppMenuItem(base::string16(), NULL, false)); | |
| 266 return items; | |
| 267 } | |
| 268 ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) override { | |
| 269 return NULL; | |
| 270 } | |
| 271 bool IsDraggable() override { return false; } | |
| 272 bool CanPin() const override { | |
| 273 return launcher_controller()->GetPinnable(app_id()) == | |
| 274 AppListControllerDelegate::PIN_EDITABLE; | |
| 275 } | |
| 276 bool ShouldShowTooltip() override { return false; } | |
| 277 | |
| 278 private: | |
| 279 DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController); | |
| 280 }; | |
| 281 | |
| 282 } // namespace | |
| 283 | |
| 284 class ChromeLauncherControllerTest : public BrowserWithTestWindowTest { | |
| 285 protected: | |
| 286 ChromeLauncherControllerTest() | |
| 287 : BrowserWithTestWindowTest(Browser::TYPE_TABBED, false), | |
| 288 test_controller_(NULL), | |
| 289 extension_service_(NULL) {} | |
| 290 | |
| 291 ~ChromeLauncherControllerTest() override {} | |
| 292 | |
| 293 void SetUp() override { | |
| 294 BrowserWithTestWindowTest::SetUp(); | |
| 295 | |
| 296 model_.reset(new ash::ShelfModel); | |
| 297 model_observer_.reset(new TestShelfModelObserver); | |
| 298 model_->AddObserver(model_observer_.get()); | |
| 299 | |
| 300 if (ash::Shell::HasInstance()) { | |
| 301 item_delegate_manager_ = | |
| 302 ash::Shell::GetInstance()->shelf_item_delegate_manager(); | |
| 303 } else { | |
| 304 item_delegate_manager_ = | |
| 305 new ash::ShelfItemDelegateManager(model_.get()); | |
| 306 } | |
| 307 | |
| 308 base::DictionaryValue manifest; | |
| 309 manifest.SetString(extensions::manifest_keys::kName, | |
| 310 "launcher controller test extension"); | |
| 311 manifest.SetString(extensions::manifest_keys::kVersion, "1"); | |
| 312 manifest.SetString(extensions::manifest_keys::kDescription, | |
| 313 "for testing pinned apps"); | |
| 314 | |
| 315 extensions::TestExtensionSystem* extension_system( | |
| 316 static_cast<extensions::TestExtensionSystem*>( | |
| 317 extensions::ExtensionSystem::Get(profile()))); | |
| 318 extension_service_ = extension_system->CreateExtensionService( | |
| 319 base::CommandLine::ForCurrentProcess(), base::FilePath(), false); | |
| 320 | |
| 321 std::string error; | |
| 322 extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 323 manifest, | |
| 324 Extension::NO_FLAGS, | |
| 325 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | |
| 326 &error); | |
| 327 extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 328 manifest, | |
| 329 Extension::NO_FLAGS, | |
| 330 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", | |
| 331 &error); | |
| 332 // Fake gmail extension. | |
| 333 base::DictionaryValue manifest_gmail; | |
| 334 manifest_gmail.SetString(extensions::manifest_keys::kName, | |
| 335 "Gmail launcher controller test extension"); | |
| 336 manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1"); | |
| 337 manifest_gmail.SetString(extensions::manifest_keys::kDescription, | |
| 338 "for testing pinned Gmail"); | |
| 339 manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL, | |
| 340 kGmailLaunchURL); | |
| 341 base::ListValue* list = new base::ListValue(); | |
| 342 list->Append(new base::StringValue("*://mail.google.com/mail/ca")); | |
| 343 manifest_gmail.Set(extensions::manifest_keys::kWebURLs, list); | |
| 344 | |
| 345 extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 346 manifest_gmail, | |
| 347 Extension::NO_FLAGS, | |
| 348 extension_misc::kGmailAppId, | |
| 349 &error); | |
| 350 | |
| 351 // Fake google docs extension. | |
| 352 extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 353 manifest, | |
| 354 Extension::NO_FLAGS, | |
| 355 extension_misc::kGoogleDocAppId, | |
| 356 &error); | |
| 357 extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 358 manifest, | |
| 359 Extension::NO_FLAGS, | |
| 360 "cccccccccccccccccccccccccccccccc", | |
| 361 &error); | |
| 362 extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 363 manifest, | |
| 364 Extension::NO_FLAGS, | |
| 365 "dddddddddddddddddddddddddddddddd", | |
| 366 &error); | |
| 367 extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 368 manifest, | |
| 369 Extension::NO_FLAGS, | |
| 370 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", | |
| 371 &error); | |
| 372 extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED, | |
| 373 manifest, | |
| 374 Extension::NO_FLAGS, | |
| 375 "ffffffffffffffffffffffffffffffff", | |
| 376 &error); | |
| 377 } | |
| 378 | |
| 379 // Creates a running V2 app (not pinned) of type |app_id|. | |
| 380 virtual void CreateRunningV2App(const std::string& app_id) { | |
| 381 DCHECK(!test_controller_); | |
| 382 ash::ShelfID id = | |
| 383 launcher_controller_->CreateAppShortcutLauncherItemWithType( | |
| 384 app_id, | |
| 385 model_->item_count(), | |
| 386 ash::TYPE_PLATFORM_APP); | |
| 387 DCHECK(id); | |
| 388 // Change the created launcher controller into a V2 app controller. | |
| 389 test_controller_ = new TestV2AppLauncherItemController(app_id, | |
| 390 launcher_controller_.get()); | |
| 391 launcher_controller_->SetItemController(id, test_controller_); | |
| 392 } | |
| 393 | |
| 394 // Sets the stage for a multi user test. | |
| 395 virtual void SetUpMultiUserScenario(base::ListValue* user_a, | |
| 396 base::ListValue* user_b) { | |
| 397 InitLauncherController(); | |
| 398 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 399 | |
| 400 // Set an empty pinned pref to begin with. | |
| 401 base::ListValue no_user; | |
| 402 SetShelfChromeIconIndex(0); | |
| 403 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 404 no_user.DeepCopy()); | |
| 405 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 406 | |
| 407 // Assume all applications have been added already. | |
| 408 extension_service_->AddExtension(extension1_.get()); | |
| 409 extension_service_->AddExtension(extension2_.get()); | |
| 410 extension_service_->AddExtension(extension3_.get()); | |
| 411 extension_service_->AddExtension(extension4_.get()); | |
| 412 extension_service_->AddExtension(extension5_.get()); | |
| 413 extension_service_->AddExtension(extension6_.get()); | |
| 414 extension_service_->AddExtension(extension7_.get()); | |
| 415 extension_service_->AddExtension(extension8_.get()); | |
| 416 // There should be nothing in the list by now. | |
| 417 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 418 | |
| 419 // Set user a preferences. | |
| 420 InsertPrefValue(user_a, 0, extension1_->id()); | |
| 421 InsertPrefValue(user_a, 1, extension2_->id()); | |
| 422 InsertPrefValue(user_a, 2, extension3_->id()); | |
| 423 InsertPrefValue(user_a, 3, extension4_->id()); | |
| 424 InsertPrefValue(user_a, 4, extension5_->id()); | |
| 425 InsertPrefValue(user_a, 5, extension6_->id()); | |
| 426 | |
| 427 // Set user b preferences. | |
| 428 InsertPrefValue(user_b, 0, extension7_->id()); | |
| 429 InsertPrefValue(user_b, 1, extension8_->id()); | |
| 430 } | |
| 431 | |
| 432 void TearDown() override { | |
| 433 arc_test_.TearDown(); | |
| 434 launcher_controller_->SetShelfItemDelegateManagerForTest(nullptr); | |
| 435 model_->RemoveObserver(model_observer_.get()); | |
| 436 model_observer_.reset(); | |
| 437 launcher_controller_.reset(); | |
| 438 | |
| 439 // item_delegate_manager_ must be deleted after launch_controller_, | |
| 440 // because launch_controller_ has a map of pointers to the data | |
| 441 // hold by item_delegate_manager_. | |
| 442 if (!ash::Shell::HasInstance()) | |
| 443 delete item_delegate_manager_; | |
| 444 | |
| 445 model_.reset(); | |
| 446 | |
| 447 BrowserWithTestWindowTest::TearDown(); | |
| 448 } | |
| 449 | |
| 450 BrowserWindow* CreateBrowserWindow() override { | |
| 451 return CreateTestBrowserWindowAura(); | |
| 452 } | |
| 453 | |
| 454 std::unique_ptr<Browser> CreateBrowserWithTestWindowForProfile( | |
| 455 Profile* profile) { | |
| 456 TestBrowserWindow* browser_window = CreateTestBrowserWindowAura(); | |
| 457 new TestBrowserWindowOwner(browser_window); | |
| 458 return base::WrapUnique( | |
| 459 CreateBrowser(profile, Browser::TYPE_TABBED, false, browser_window)); | |
| 460 } | |
| 461 | |
| 462 void AddAppListLauncherItem() { | |
| 463 ash::ShelfItem app_list; | |
| 464 app_list.type = ash::TYPE_APP_LIST; | |
| 465 model_->Add(app_list); | |
| 466 } | |
| 467 | |
| 468 void InitLauncherController() { | |
| 469 AddAppListLauncherItem(); | |
| 470 launcher_controller_.reset( | |
| 471 new ChromeLauncherController(profile(), model_.get())); | |
| 472 if (!ash::Shell::HasInstance()) | |
| 473 SetShelfItemDelegateManager(item_delegate_manager_); | |
| 474 launcher_controller_->Init(); | |
| 475 } | |
| 476 | |
| 477 void InitLauncherControllerWithBrowser() { | |
| 478 InitLauncherController(); | |
| 479 chrome::NewTab(browser()); | |
| 480 browser()->window()->Show(); | |
| 481 } | |
| 482 | |
| 483 void SetAppIconLoader(std::unique_ptr<AppIconLoader> loader) { | |
| 484 std::vector<std::unique_ptr<AppIconLoader>> loaders; | |
| 485 loaders.push_back(std::move(loader)); | |
| 486 launcher_controller_->SetAppIconLoadersForTest(loaders); | |
| 487 } | |
| 488 | |
| 489 void SetAppIconLoaders(std::unique_ptr<AppIconLoader> loader1, | |
| 490 std::unique_ptr<AppIconLoader> loader2) { | |
| 491 std::vector<std::unique_ptr<AppIconLoader>> loaders; | |
| 492 loaders.push_back(std::move(loader1)); | |
| 493 loaders.push_back(std::move(loader2)); | |
| 494 launcher_controller_->SetAppIconLoadersForTest(loaders); | |
| 495 } | |
| 496 | |
| 497 void SetLauncherControllerHelper(LauncherControllerHelper* helper) { | |
| 498 launcher_controller_->SetLauncherControllerHelperForTest(helper); | |
| 499 } | |
| 500 | |
| 501 void SetShelfItemDelegateManager(ash::ShelfItemDelegateManager* manager) { | |
| 502 launcher_controller_->SetShelfItemDelegateManagerForTest(manager); | |
| 503 } | |
| 504 | |
| 505 void InsertPrefValue(base::ListValue* pref_value, | |
| 506 int index, | |
| 507 const std::string& extension_id) { | |
| 508 base::DictionaryValue* entry = new base::DictionaryValue(); | |
| 509 entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id); | |
| 510 pref_value->Insert(index, entry); | |
| 511 } | |
| 512 | |
| 513 // Gets the currently configured app launchers from the controller. | |
| 514 void GetAppLaunchers(ChromeLauncherController* controller, | |
| 515 std::vector<std::string>* launchers) { | |
| 516 launchers->clear(); | |
| 517 for (ash::ShelfItems::const_iterator iter(model_->items().begin()); | |
| 518 iter != model_->items().end(); ++iter) { | |
| 519 ChromeLauncherController::IDToItemControllerMap::const_iterator | |
| 520 entry(controller->id_to_item_controller_map_.find(iter->id)); | |
| 521 if (iter->type == ash::TYPE_APP_SHORTCUT && | |
| 522 entry != controller->id_to_item_controller_map_.end()) { | |
| 523 launchers->push_back(entry->second->app_id()); | |
| 524 } | |
| 525 } | |
| 526 } | |
| 527 | |
| 528 // Get the setup of the currently shown launcher items in one string. | |
| 529 // Each pinned element will start with a big letter, each running but not | |
| 530 // pinned V1 app will start with a small letter and each running but not | |
| 531 // pinned V2 app will start with a '*' + small letter. | |
| 532 std::string GetPinnedAppStatus() { | |
| 533 std::string result; | |
| 534 for (int i = 0; i < model_->item_count(); i++) { | |
| 535 if (!result.empty()) | |
| 536 result.append(", "); | |
| 537 switch (model_->items()[i].type) { | |
| 538 case ash::TYPE_PLATFORM_APP: | |
| 539 result += "*"; | |
| 540 // FALLTHROUGH | |
| 541 case ash::TYPE_WINDOWED_APP: { | |
| 542 const std::string& app = | |
| 543 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id); | |
| 544 if (app == extension1_->id()) { | |
| 545 result += "app1"; | |
| 546 EXPECT_FALSE( | |
| 547 launcher_controller_->IsAppPinned(extension1_->id())); | |
| 548 } else if (app == extension2_->id()) { | |
| 549 result += "app2"; | |
| 550 EXPECT_FALSE( | |
| 551 launcher_controller_->IsAppPinned(extension2_->id())); | |
| 552 } else if (app == extension3_->id()) { | |
| 553 result += "app3"; | |
| 554 EXPECT_FALSE( | |
| 555 launcher_controller_->IsAppPinned(extension3_->id())); | |
| 556 } else if (app == extension4_->id()) { | |
| 557 result += "app4"; | |
| 558 EXPECT_FALSE( | |
| 559 launcher_controller_->IsAppPinned(extension4_->id())); | |
| 560 } else if (app == extension5_->id()) { | |
| 561 result += "app5"; | |
| 562 EXPECT_FALSE( | |
| 563 launcher_controller_->IsAppPinned(extension5_->id())); | |
| 564 } else if (app == extension6_->id()) { | |
| 565 result += "app6"; | |
| 566 EXPECT_FALSE( | |
| 567 launcher_controller_->IsAppPinned(extension6_->id())); | |
| 568 } else if (app == extension7_->id()) { | |
| 569 result += "app7"; | |
| 570 EXPECT_FALSE( | |
| 571 launcher_controller_->IsAppPinned(extension7_->id())); | |
| 572 } else if (app == extension8_->id()) { | |
| 573 result += "app8"; | |
| 574 EXPECT_FALSE( | |
| 575 launcher_controller_->IsAppPinned(extension8_->id())); | |
| 576 } else { | |
| 577 result += "unknown"; | |
| 578 } | |
| 579 break; | |
| 580 } | |
| 581 case ash::TYPE_APP_SHORTCUT: { | |
| 582 const std::string& app = | |
| 583 launcher_controller_->GetAppIDForShelfID(model_->items()[i].id); | |
| 584 if (app == extension1_->id()) { | |
| 585 result += "App1"; | |
| 586 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 587 } else if (app == extension2_->id()) { | |
| 588 result += "App2"; | |
| 589 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 590 } else if (app == extension3_->id()) { | |
| 591 result += "App3"; | |
| 592 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 593 } else if (app == extension4_->id()) { | |
| 594 result += "App4"; | |
| 595 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); | |
| 596 } else if (app == extension5_->id()) { | |
| 597 result += "App5"; | |
| 598 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension5_->id())); | |
| 599 } else if (app == extension6_->id()) { | |
| 600 result += "App6"; | |
| 601 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension6_->id())); | |
| 602 } else if (app == extension7_->id()) { | |
| 603 result += "App7"; | |
| 604 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension7_->id())); | |
| 605 } else if (app == extension8_->id()) { | |
| 606 result += "App8"; | |
| 607 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension8_->id())); | |
| 608 } else if (app == ArcAppTest::GetAppId(arc_test_.fake_apps()[0])) { | |
| 609 result += arc_test_.fake_apps()[0].name; | |
| 610 } else { | |
| 611 result += "unknown"; | |
| 612 } | |
| 613 break; | |
| 614 } | |
| 615 case ash::TYPE_BROWSER_SHORTCUT: | |
| 616 result += "Chrome"; | |
| 617 break; | |
| 618 case ash::TYPE_APP_LIST: | |
| 619 result += "AppList"; | |
| 620 break; | |
| 621 default: | |
| 622 result += "Unknown"; | |
| 623 break; | |
| 624 } | |
| 625 } | |
| 626 return result; | |
| 627 } | |
| 628 | |
| 629 // Set the index at which the chrome icon should be. | |
| 630 void SetShelfChromeIconIndex(int index) { | |
| 631 profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex, | |
| 632 index); | |
| 633 } | |
| 634 | |
| 635 // Remember the order of unpinned but running applications for the current | |
| 636 // user. | |
| 637 void RememberUnpinnedRunningApplicationOrder() { | |
| 638 launcher_controller_->RememberUnpinnedRunningApplicationOrder(); | |
| 639 } | |
| 640 | |
| 641 // Restore the order of running but unpinned applications for a given user. | |
| 642 void RestoreUnpinnedRunningApplicationOrder(const AccountId& account_id) { | |
| 643 launcher_controller_->RestoreUnpinnedRunningApplicationOrder( | |
| 644 account_id.GetUserEmail()); | |
| 645 } | |
| 646 | |
| 647 void SendListOfArcApps() { | |
| 648 arc_test_.app_instance()->RefreshAppList(); | |
| 649 arc_test_.app_instance()->SendRefreshAppList(arc_test_.fake_apps()); | |
| 650 } | |
| 651 | |
| 652 void UninstallArcApps() { | |
| 653 arc_test_.app_instance()->RefreshAppList(); | |
| 654 arc_test_.app_instance()->SendRefreshAppList( | |
| 655 std::vector<arc::mojom::AppInfo>()); | |
| 656 } | |
| 657 | |
| 658 void EnableArc(bool enable) { | |
| 659 enable ? arc_test_.arc_auth_service()->EnableArc() | |
| 660 : arc_test_.arc_auth_service()->DisableArc(); | |
| 661 base::RunLoop().RunUntilIdle(); | |
| 662 } | |
| 663 | |
| 664 // Creates app window and set optional Arc application id. | |
| 665 views::Widget* CreateAppWindow(std::string* window_app_id) { | |
| 666 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); | |
| 667 params.bounds = gfx::Rect(5, 5, 20, 20); | |
| 668 views::Widget* widget = new views::Widget(); | |
| 669 widget->Init(params); | |
| 670 widget->Show(); | |
| 671 widget->Activate(); | |
| 672 if (window_app_id) { | |
| 673 exo::ShellSurface::SetApplicationId(widget->GetNativeWindow(), | |
| 674 window_app_id); | |
| 675 } | |
| 676 return widget; | |
| 677 } | |
| 678 | |
| 679 // Needed for extension service & friends to work. | |
| 680 scoped_refptr<Extension> extension1_; | |
| 681 scoped_refptr<Extension> extension2_; | |
| 682 scoped_refptr<Extension> extension3_; | |
| 683 scoped_refptr<Extension> extension4_; | |
| 684 scoped_refptr<Extension> extension5_; | |
| 685 scoped_refptr<Extension> extension6_; | |
| 686 scoped_refptr<Extension> extension7_; | |
| 687 scoped_refptr<Extension> extension8_; | |
| 688 | |
| 689 ArcAppTest arc_test_; | |
| 690 std::unique_ptr<ChromeLauncherController> launcher_controller_; | |
| 691 std::unique_ptr<TestShelfModelObserver> model_observer_; | |
| 692 std::unique_ptr<ash::ShelfModel> model_; | |
| 693 | |
| 694 // |item_delegate_manager_| owns |test_controller_|. | |
| 695 LauncherItemController* test_controller_; | |
| 696 | |
| 697 ExtensionService* extension_service_; | |
| 698 | |
| 699 ash::ShelfItemDelegateManager* item_delegate_manager_; | |
| 700 | |
| 701 private: | |
| 702 TestBrowserWindow* CreateTestBrowserWindowAura() { | |
| 703 std::unique_ptr<aura::Window> window(new aura::Window(nullptr)); | |
| 704 window->set_id(0); | |
| 705 window->SetType(ui::wm::WINDOW_TYPE_NORMAL); | |
| 706 window->Init(ui::LAYER_TEXTURED); | |
| 707 aura::client::ParentWindowWithContext(window.get(), GetContext(), | |
| 708 gfx::Rect(200, 200)); | |
| 709 | |
| 710 return new TestBrowserWindowAura(std::move(window)); | |
| 711 } | |
| 712 | |
| 713 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerTest); | |
| 714 }; | |
| 715 | |
| 716 // Watches WebContents and blocks until it is destroyed. This is needed for | |
| 717 // the destruction of a V2 application. | |
| 718 class WebContentsDestroyedWatcher : public content::WebContentsObserver { | |
| 719 public: | |
| 720 explicit WebContentsDestroyedWatcher(content::WebContents* web_contents) | |
| 721 : content::WebContentsObserver(web_contents), | |
| 722 message_loop_runner_(new content::MessageLoopRunner) { | |
| 723 EXPECT_TRUE(web_contents != NULL); | |
| 724 } | |
| 725 ~WebContentsDestroyedWatcher() override {} | |
| 726 | |
| 727 // Waits until the WebContents is destroyed. | |
| 728 void Wait() { | |
| 729 message_loop_runner_->Run(); | |
| 730 } | |
| 731 | |
| 732 private: | |
| 733 // Overridden WebContentsObserver methods. | |
| 734 void WebContentsDestroyed() override { message_loop_runner_->Quit(); } | |
| 735 | |
| 736 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
| 737 | |
| 738 DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedWatcher); | |
| 739 }; | |
| 740 | |
| 741 // A V1 windowed application. | |
| 742 class V1App : public TestBrowserWindow { | |
| 743 public: | |
| 744 V1App(Profile* profile, const std::string& app_name) { | |
| 745 // Create a window. | |
| 746 native_window_.reset(new aura::Window(NULL)); | |
| 747 native_window_->set_id(0); | |
| 748 native_window_->SetType(ui::wm::WINDOW_TYPE_POPUP); | |
| 749 native_window_->Init(ui::LAYER_TEXTURED); | |
| 750 native_window_->Show(); | |
| 751 aura::client::ParentWindowWithContext(native_window_.get(), | |
| 752 ash::Shell::GetPrimaryRootWindow(), | |
| 753 gfx::Rect(10, 10, 20, 30)); | |
| 754 Browser::CreateParams params = Browser::CreateParams::CreateForApp( | |
| 755 kCrxAppPrefix + app_name, true /* trusted_source */, gfx::Rect(), | |
| 756 profile); | |
| 757 params.window = this; | |
| 758 browser_.reset(new Browser(params)); | |
| 759 chrome::AddTabAt(browser_.get(), GURL(), 0, true); | |
| 760 } | |
| 761 | |
| 762 ~V1App() override { | |
| 763 // close all tabs. Note that we do not need to destroy the browser itself. | |
| 764 browser_->tab_strip_model()->CloseAllTabs(); | |
| 765 } | |
| 766 | |
| 767 Browser* browser() { return browser_.get(); } | |
| 768 | |
| 769 // TestBrowserWindow override: | |
| 770 gfx::NativeWindow GetNativeWindow() const override { | |
| 771 return native_window_.get(); | |
| 772 } | |
| 773 | |
| 774 private: | |
| 775 // The associated browser with this app. | |
| 776 std::unique_ptr<Browser> browser_; | |
| 777 | |
| 778 // The native window we use. | |
| 779 std::unique_ptr<aura::Window> native_window_; | |
| 780 | |
| 781 DISALLOW_COPY_AND_ASSIGN(V1App); | |
| 782 }; | |
| 783 | |
| 784 // A V2 application which gets created with an |extension| and for a |profile|. | |
| 785 // Upon destruction it will properly close the application. | |
| 786 class V2App { | |
| 787 public: | |
| 788 V2App(Profile* profile, const extensions::Extension* extension) | |
| 789 : creator_web_contents_( | |
| 790 content::WebContentsTester::CreateTestWebContents(profile, | |
| 791 nullptr)) { | |
| 792 window_ = new extensions::AppWindow(profile, new ChromeAppDelegate(true), | |
| 793 extension); | |
| 794 extensions::AppWindow::CreateParams params = | |
| 795 extensions::AppWindow::CreateParams(); | |
| 796 // Note: normally, the creator RFH is the background page of the | |
| 797 // app/extension | |
| 798 // calling chrome.app.window.create. For unit testing purposes, just passing | |
| 799 // in a random RenderFrameHost is Good Enoughâ„¢. | |
| 800 window_->Init(GURL(std::string()), | |
| 801 new extensions::AppWindowContentsImpl(window_), | |
| 802 creator_web_contents_->GetMainFrame(), params); | |
| 803 } | |
| 804 | |
| 805 virtual ~V2App() { | |
| 806 WebContentsDestroyedWatcher destroyed_watcher(window_->web_contents()); | |
| 807 window_->GetBaseWindow()->Close(); | |
| 808 destroyed_watcher.Wait(); | |
| 809 } | |
| 810 | |
| 811 extensions::AppWindow* window() { return window_; } | |
| 812 | |
| 813 private: | |
| 814 std::unique_ptr<content::WebContents> creator_web_contents_; | |
| 815 | |
| 816 // The app window which represents the application. Note that the window | |
| 817 // deletes itself asynchronously after window_->GetBaseWindow()->Close() gets | |
| 818 // called. | |
| 819 extensions::AppWindow* window_; | |
| 820 | |
| 821 DISALLOW_COPY_AND_ASSIGN(V2App); | |
| 822 }; | |
| 823 | |
| 824 // The testing framework to test multi profile scenarios. | |
| 825 class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest | |
| 826 : public ChromeLauncherControllerTest { | |
| 827 protected: | |
| 828 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() { | |
| 829 } | |
| 830 | |
| 831 ~MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest() override {} | |
| 832 | |
| 833 // Overwrite the Setup function to enable multi profile and needed objects. | |
| 834 void SetUp() override { | |
| 835 profile_manager_.reset( | |
| 836 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); | |
| 837 | |
| 838 ASSERT_TRUE(profile_manager_->SetUp()); | |
| 839 | |
| 840 // AvatarMenu and multiple profiles works after user logged in. | |
| 841 profile_manager_->SetLoggedIn(true); | |
| 842 | |
| 843 // Initialize the UserManager singleton to a fresh FakeUserManager instance. | |
| 844 user_manager_enabler_.reset(new chromeos::ScopedUserManagerEnabler( | |
| 845 new chromeos::FakeChromeUserManager)); | |
| 846 | |
| 847 // Initialize the WallpaperManager singleton. | |
| 848 chromeos::WallpaperManager::Initialize(); | |
| 849 | |
| 850 // Initialize the rest. | |
| 851 ChromeLauncherControllerTest::SetUp(); | |
| 852 | |
| 853 // Get some base objects. | |
| 854 session_delegate()->set_logged_in_users(2); | |
| 855 shell_delegate_ = static_cast<ash::test::TestShellDelegate*>( | |
| 856 ash::Shell::GetInstance()->delegate()); | |
| 857 shell_delegate_->set_multi_profiles_enabled(true); | |
| 858 } | |
| 859 | |
| 860 void TearDown() override { | |
| 861 ChromeLauncherControllerTest::TearDown(); | |
| 862 user_manager_enabler_.reset(); | |
| 863 for (ProfileToNameMap::iterator it = created_profiles_.begin(); | |
| 864 it != created_profiles_.end(); ++it) | |
| 865 profile_manager_->DeleteTestingProfile(it->second); | |
| 866 chromeos::WallpaperManager::Shutdown(); | |
| 867 | |
| 868 // A Task is leaked if we don't destroy everything, then run the message | |
| 869 // loop. | |
| 870 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 871 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 872 base::MessageLoop::current()->Run(); | |
| 873 } | |
| 874 | |
| 875 // Creates a profile for a given |user_name|. Note that this class will keep | |
| 876 // the ownership of the created object. | |
| 877 TestingProfile* CreateMultiUserProfile(const std::string& user_name) { | |
| 878 const std::string email_string = user_name + "@example.com"; | |
| 879 const AccountId account_id(AccountId::FromUserEmail(email_string)); | |
| 880 static_cast<ash::test::TestSessionStateDelegate*>( | |
| 881 ash::Shell::GetInstance()->session_state_delegate()) | |
| 882 ->AddUser(account_id); | |
| 883 // Add a user to the fake user manager. | |
| 884 session_delegate()->AddUser(account_id); | |
| 885 GetFakeUserManager()->AddUser(account_id); | |
| 886 | |
| 887 GetFakeUserManager()->LoginUser(account_id); | |
| 888 | |
| 889 TestingProfile* profile = | |
| 890 profile_manager()->CreateTestingProfile(account_id.GetUserEmail()); | |
| 891 EXPECT_TRUE(profile); | |
| 892 | |
| 893 // Remember the profile name so that we can destroy it upon destruction. | |
| 894 created_profiles_[profile] = account_id.GetUserEmail(); | |
| 895 if (chrome::MultiUserWindowManager::GetInstance()) | |
| 896 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile); | |
| 897 if (launcher_controller_) | |
| 898 launcher_controller_->AdditionalUserAddedToSession(profile); | |
| 899 return profile; | |
| 900 } | |
| 901 | |
| 902 // Switch to another user. | |
| 903 void SwitchActiveUser(const AccountId& account_id) { | |
| 904 session_delegate()->SwitchActiveUser(account_id); | |
| 905 GetFakeUserManager()->SwitchActiveUser(account_id); | |
| 906 chrome::MultiUserWindowManagerChromeOS* manager = | |
| 907 static_cast<chrome::MultiUserWindowManagerChromeOS*>( | |
| 908 chrome::MultiUserWindowManager::GetInstance()); | |
| 909 manager->SetAnimationSpeedForTest( | |
| 910 chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED); | |
| 911 manager->ActiveUserChanged(account_id); | |
| 912 launcher_controller_->browser_status_monitor_for_test()->ActiveUserChanged( | |
| 913 account_id.GetUserEmail()); | |
| 914 launcher_controller_->app_window_controller_for_test()->ActiveUserChanged( | |
| 915 account_id.GetUserEmail()); | |
| 916 } | |
| 917 | |
| 918 // Creates a browser with a |profile| and load a tab with a |title| and |url|. | |
| 919 std::unique_ptr<Browser> CreateBrowserAndTabWithProfile( | |
| 920 Profile* profile, | |
| 921 const std::string& title, | |
| 922 const std::string& url) { | |
| 923 std::unique_ptr<Browser> browser( | |
| 924 CreateBrowserWithTestWindowForProfile(profile)); | |
| 925 chrome::NewTab(browser.get()); | |
| 926 | |
| 927 browser->window()->Show(); | |
| 928 NavigateAndCommitActiveTabWithTitle(browser.get(), GURL(url), | |
| 929 ASCIIToUTF16(title)); | |
| 930 return browser; | |
| 931 } | |
| 932 | |
| 933 // Creates a running V1 application. | |
| 934 // Note that with the use of the launcher_controller_helper as done below, | |
| 935 // this is only usable with a single v1 application. | |
| 936 V1App* CreateRunningV1App(Profile* profile, | |
| 937 const std::string& app_name, | |
| 938 const std::string& url) { | |
| 939 V1App* v1_app = new V1App(profile, app_name); | |
| 940 // Create a new launcher controller helper and assign it to the launcher so | |
| 941 // that this app gets properly detected. | |
| 942 // TODO(skuhne): Create a more intelligent launcher contrller helper that is | |
| 943 // able to detect all running apps properly. | |
| 944 TestLauncherControllerHelper* helper = new TestLauncherControllerHelper; | |
| 945 helper->SetAppID(v1_app->browser()->tab_strip_model()->GetWebContentsAt(0), | |
| 946 app_name); | |
| 947 SetLauncherControllerHelper(helper); | |
| 948 | |
| 949 NavigateAndCommitActiveTabWithTitle( | |
| 950 v1_app->browser(), GURL(url), ASCIIToUTF16("")); | |
| 951 return v1_app; | |
| 952 } | |
| 953 | |
| 954 ash::test::TestSessionStateDelegate* session_delegate() { | |
| 955 return static_cast<ash::test::TestSessionStateDelegate*>( | |
| 956 ash::Shell::GetInstance()->session_state_delegate()); | |
| 957 } | |
| 958 ash::test::TestShellDelegate* shell_delegate() { return shell_delegate_; } | |
| 959 | |
| 960 // Override BrowserWithTestWindowTest: | |
| 961 TestingProfile* CreateProfile() override { | |
| 962 return CreateMultiUserProfile("user1"); | |
| 963 } | |
| 964 void DestroyProfile(TestingProfile* profile) override { | |
| 965 // Delete the profile through our profile manager. | |
| 966 ProfileToNameMap::iterator it = created_profiles_.find(profile); | |
| 967 DCHECK(it != created_profiles_.end()); | |
| 968 profile_manager_->DeleteTestingProfile(it->second); | |
| 969 created_profiles_.erase(it); | |
| 970 } | |
| 971 | |
| 972 private: | |
| 973 typedef std::map<Profile*, std::string> ProfileToNameMap; | |
| 974 TestingProfileManager* profile_manager() { return profile_manager_.get(); } | |
| 975 | |
| 976 chromeos::FakeChromeUserManager* GetFakeUserManager() { | |
| 977 return static_cast<chromeos::FakeChromeUserManager*>( | |
| 978 user_manager::UserManager::Get()); | |
| 979 } | |
| 980 | |
| 981 std::unique_ptr<TestingProfileManager> profile_manager_; | |
| 982 std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; | |
| 983 | |
| 984 ash::test::TestShellDelegate* shell_delegate_; | |
| 985 | |
| 986 ProfileToNameMap created_profiles_; | |
| 987 | |
| 988 DISALLOW_COPY_AND_ASSIGN( | |
| 989 MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest); | |
| 990 }; | |
| 991 | |
| 992 TEST_F(ChromeLauncherControllerTest, DefaultApps) { | |
| 993 InitLauncherController(); | |
| 994 // Model should only contain the browser shortcut and app list items. | |
| 995 EXPECT_EQ(2, model_->item_count()); | |
| 996 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 997 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 998 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 999 | |
| 1000 // Installing |extension3_| should add it to the launcher - behind the | |
| 1001 // chrome icon. | |
| 1002 extension_service_->AddExtension(extension3_.get()); | |
| 1003 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus()); | |
| 1004 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1005 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1006 } | |
| 1007 | |
| 1008 /* | |
| 1009 * Test ChromeLauncherController correctly merges policy pinned apps | |
| 1010 * and user pinned apps | |
| 1011 */ | |
| 1012 TEST_F(ChromeLauncherControllerTest, MergePolicyAndUserPrefPinnedApps) { | |
| 1013 InitLauncherController(); | |
| 1014 | |
| 1015 base::ListValue user_pref_value; | |
| 1016 extension_service_->AddExtension(extension1_.get()); | |
| 1017 extension_service_->AddExtension(extension3_.get()); | |
| 1018 extension_service_->AddExtension(extension4_.get()); | |
| 1019 extension_service_->AddExtension(extension5_.get()); | |
| 1020 // extension 1, 3 are pinned by user | |
| 1021 InsertPrefValue(&user_pref_value, 0, extension1_->id()); | |
| 1022 InsertPrefValue(&user_pref_value, 1, extension3_->id()); | |
| 1023 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1024 user_pref_value.DeepCopy()); | |
| 1025 | |
| 1026 base::ListValue policy_value; | |
| 1027 // extension 2 4 are pinned by policy | |
| 1028 InsertPrefValue(&policy_value, 0, extension2_->id()); | |
| 1029 InsertPrefValue(&policy_value, 1, extension4_->id()); | |
| 1030 profile()->GetTestingPrefService()->SetManagedPref( | |
| 1031 prefs::kPolicyPinnedLauncherApps, policy_value.DeepCopy()); | |
| 1032 | |
| 1033 SetShelfChromeIconIndex(1); | |
| 1034 | |
| 1035 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1036 // 2 is not pinned as it's not installed | |
| 1037 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1038 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1039 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); | |
| 1040 // install extension 2 and check | |
| 1041 extension_service_->AddExtension(extension2_.get()); | |
| 1042 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1043 | |
| 1044 // Check user can manually pin or unpin these apps | |
| 1045 EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE, | |
| 1046 launcher_controller_->GetPinnable(extension1_->id())); | |
| 1047 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED, | |
| 1048 launcher_controller_->GetPinnable(extension2_->id())); | |
| 1049 EXPECT_EQ(AppListControllerDelegate::PIN_EDITABLE, | |
| 1050 launcher_controller_->GetPinnable(extension3_->id())); | |
| 1051 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED, | |
| 1052 launcher_controller_->GetPinnable(extension4_->id())); | |
| 1053 | |
| 1054 // Check the order of shelf pinned apps | |
| 1055 EXPECT_EQ("AppList, App2, App4, App1, Chrome, App3", GetPinnedAppStatus()); | |
| 1056 } | |
| 1057 | |
| 1058 // Check that the restauration of launcher items is happening in the same order | |
| 1059 // as the user has pinned them (on another system) when they are synced reverse | |
| 1060 // order. | |
| 1061 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsReverseOrder) { | |
| 1062 InitLauncherController(); | |
| 1063 | |
| 1064 base::ListValue policy_value; | |
| 1065 InsertPrefValue(&policy_value, 0, extension1_->id()); | |
| 1066 InsertPrefValue(&policy_value, 1, extension2_->id()); | |
| 1067 InsertPrefValue(&policy_value, 2, extension3_->id()); | |
| 1068 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1069 policy_value.DeepCopy()); | |
| 1070 SetShelfChromeIconIndex(0); | |
| 1071 // Model should only contain the browser shortcut and app list items. | |
| 1072 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1073 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1074 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1075 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 1076 | |
| 1077 // Installing |extension3_| should add it to the shelf - behind the | |
| 1078 // chrome icon. | |
| 1079 ash::ShelfItem item; | |
| 1080 extension_service_->AddExtension(extension3_.get()); | |
| 1081 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1082 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1083 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus()); | |
| 1084 | |
| 1085 // Installing |extension2_| should add it to the launcher - behind the | |
| 1086 // chrome icon, but in first location. | |
| 1087 extension_service_->AddExtension(extension2_.get()); | |
| 1088 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1089 EXPECT_EQ("AppList, Chrome, App2, App3", GetPinnedAppStatus()); | |
| 1090 | |
| 1091 // Installing |extension1_| should add it to the launcher - behind the | |
| 1092 // chrome icon, but in first location. | |
| 1093 extension_service_->AddExtension(extension1_.get()); | |
| 1094 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus()); | |
| 1095 } | |
| 1096 | |
| 1097 // Check that the restauration of launcher items is happening in the same order | |
| 1098 // as the user has pinned them (on another system) when they are synced random | |
| 1099 // order. | |
| 1100 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrder) { | |
| 1101 InitLauncherController(); | |
| 1102 | |
| 1103 base::ListValue policy_value; | |
| 1104 InsertPrefValue(&policy_value, 0, extension1_->id()); | |
| 1105 InsertPrefValue(&policy_value, 1, extension2_->id()); | |
| 1106 InsertPrefValue(&policy_value, 2, extension3_->id()); | |
| 1107 | |
| 1108 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1109 policy_value.DeepCopy()); | |
| 1110 SetShelfChromeIconIndex(0); | |
| 1111 // Model should only contain the browser shortcut and app list items. | |
| 1112 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1113 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1114 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1115 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 1116 | |
| 1117 // Installing |extension2_| should add it to the launcher - behind the | |
| 1118 // chrome icon. | |
| 1119 extension_service_->AddExtension(extension2_.get()); | |
| 1120 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1121 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1122 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus()); | |
| 1123 | |
| 1124 // Installing |extension1_| should add it to the launcher - behind the | |
| 1125 // chrome icon, but in first location. | |
| 1126 extension_service_->AddExtension(extension1_.get()); | |
| 1127 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1128 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1129 | |
| 1130 // Installing |extension3_| should add it to the launcher - behind the | |
| 1131 // chrome icon, but in first location. | |
| 1132 extension_service_->AddExtension(extension3_.get()); | |
| 1133 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus()); | |
| 1134 } | |
| 1135 | |
| 1136 // Check that the restauration of launcher items is happening in the same order | |
| 1137 // as the user has pinned / moved them (on another system) when they are synced | |
| 1138 // random order - including the chrome icon. | |
| 1139 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrderChromeMoved) { | |
| 1140 InitLauncherController(); | |
| 1141 | |
| 1142 base::ListValue policy_value; | |
| 1143 InsertPrefValue(&policy_value, 0, extension1_->id()); | |
| 1144 InsertPrefValue(&policy_value, 1, extension2_->id()); | |
| 1145 InsertPrefValue(&policy_value, 2, extension3_->id()); | |
| 1146 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1147 policy_value.DeepCopy()); | |
| 1148 SetShelfChromeIconIndex(1); | |
| 1149 // Model should only contain the browser shortcut and app list items. | |
| 1150 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1151 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1152 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1153 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 1154 | |
| 1155 // Installing |extension2_| should add it to the shelf - behind the | |
| 1156 // chrome icon. | |
| 1157 ash::ShelfItem item; | |
| 1158 extension_service_->AddExtension(extension2_.get()); | |
| 1159 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1160 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1161 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus()); | |
| 1162 | |
| 1163 // Installing |extension1_| should add it to the launcher - behind the | |
| 1164 // chrome icon, but in first location. | |
| 1165 extension_service_->AddExtension(extension1_.get()); | |
| 1166 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 1167 EXPECT_EQ("AppList, App1, Chrome, App2", GetPinnedAppStatus()); | |
| 1168 | |
| 1169 // Installing |extension3_| should add it to the launcher - behind the | |
| 1170 // chrome icon, but in first location. | |
| 1171 extension_service_->AddExtension(extension3_.get()); | |
| 1172 EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus()); | |
| 1173 } | |
| 1174 | |
| 1175 // Check that syncing to a different state does the correct thing. | |
| 1176 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsResyncOrder) { | |
| 1177 InitLauncherController(); | |
| 1178 base::ListValue policy_value; | |
| 1179 InsertPrefValue(&policy_value, 0, extension1_->id()); | |
| 1180 InsertPrefValue(&policy_value, 1, extension2_->id()); | |
| 1181 InsertPrefValue(&policy_value, 2, extension3_->id()); | |
| 1182 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1183 policy_value.DeepCopy()); | |
| 1184 // The shelf layout has always one static item at the beginning (App List). | |
| 1185 SetShelfChromeIconIndex(0); | |
| 1186 extension_service_->AddExtension(extension2_.get()); | |
| 1187 EXPECT_EQ("AppList, Chrome, App2", GetPinnedAppStatus()); | |
| 1188 extension_service_->AddExtension(extension1_.get()); | |
| 1189 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1190 extension_service_->AddExtension(extension3_.get()); | |
| 1191 EXPECT_EQ("AppList, Chrome, App1, App2, App3", GetPinnedAppStatus()); | |
| 1192 | |
| 1193 // Change the order with increasing chrome position and decreasing position. | |
| 1194 base::ListValue policy_value1; | |
| 1195 InsertPrefValue(&policy_value1, 0, extension3_->id()); | |
| 1196 InsertPrefValue(&policy_value1, 1, extension1_->id()); | |
| 1197 InsertPrefValue(&policy_value1, 2, extension2_->id()); | |
| 1198 SetShelfChromeIconIndex(3); | |
| 1199 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1200 policy_value1.DeepCopy()); | |
| 1201 EXPECT_EQ("AppList, App3, App1, App2, Chrome", GetPinnedAppStatus()); | |
| 1202 base::ListValue policy_value2; | |
| 1203 InsertPrefValue(&policy_value2, 0, extension2_->id()); | |
| 1204 InsertPrefValue(&policy_value2, 1, extension3_->id()); | |
| 1205 InsertPrefValue(&policy_value2, 2, extension1_->id()); | |
| 1206 SetShelfChromeIconIndex(2); | |
| 1207 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1208 policy_value2.DeepCopy()); | |
| 1209 EXPECT_EQ("AppList, App2, App3, Chrome, App1", GetPinnedAppStatus()); | |
| 1210 | |
| 1211 // Check that the chrome icon can also be at the first possible location. | |
| 1212 SetShelfChromeIconIndex(0); | |
| 1213 base::ListValue policy_value3; | |
| 1214 InsertPrefValue(&policy_value3, 0, extension3_->id()); | |
| 1215 InsertPrefValue(&policy_value3, 1, extension2_->id()); | |
| 1216 InsertPrefValue(&policy_value3, 2, extension1_->id()); | |
| 1217 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1218 policy_value3.DeepCopy()); | |
| 1219 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus()); | |
| 1220 | |
| 1221 // Check that unloading of extensions works as expected. | |
| 1222 extension_service_->UnloadExtension(extension1_->id(), | |
| 1223 UnloadedExtensionInfo::REASON_UNINSTALL); | |
| 1224 EXPECT_EQ("AppList, Chrome, App3, App2", GetPinnedAppStatus()); | |
| 1225 | |
| 1226 extension_service_->UnloadExtension(extension2_->id(), | |
| 1227 UnloadedExtensionInfo::REASON_UNINSTALL); | |
| 1228 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus()); | |
| 1229 | |
| 1230 // Check that an update of an extension does not crash the system. | |
| 1231 extension_service_->UnloadExtension(extension3_->id(), | |
| 1232 UnloadedExtensionInfo::REASON_UPDATE); | |
| 1233 EXPECT_EQ("AppList, Chrome, App3", GetPinnedAppStatus()); | |
| 1234 } | |
| 1235 | |
| 1236 // Check that simple locking of an application will 'create' a launcher item. | |
| 1237 TEST_F(ChromeLauncherControllerTest, CheckLockApps) { | |
| 1238 InitLauncherController(); | |
| 1239 // Model should only contain the browser shortcut and app list items. | |
| 1240 EXPECT_EQ(2, model_->item_count()); | |
| 1241 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1242 EXPECT_FALSE( | |
| 1243 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1244 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1245 EXPECT_FALSE( | |
| 1246 launcher_controller_->IsWindowedAppInLauncher(extension2_->id())); | |
| 1247 | |
| 1248 launcher_controller_->LockV1AppWithID(extension1_->id()); | |
| 1249 | |
| 1250 EXPECT_EQ(3, model_->item_count()); | |
| 1251 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type); | |
| 1252 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1253 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1254 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1255 EXPECT_FALSE( | |
| 1256 launcher_controller_->IsWindowedAppInLauncher(extension2_->id())); | |
| 1257 | |
| 1258 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1259 | |
| 1260 EXPECT_EQ(2, model_->item_count()); | |
| 1261 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1262 EXPECT_FALSE( | |
| 1263 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1264 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1265 EXPECT_FALSE( | |
| 1266 launcher_controller_->IsWindowedAppInLauncher(extension2_->id())); | |
| 1267 } | |
| 1268 | |
| 1269 // Check that multiple locks of an application will be properly handled. | |
| 1270 TEST_F(ChromeLauncherControllerTest, CheckMultiLockApps) { | |
| 1271 InitLauncherController(); | |
| 1272 // Model should only contain the browser shortcut and app list items. | |
| 1273 EXPECT_EQ(2, model_->item_count()); | |
| 1274 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1275 EXPECT_FALSE( | |
| 1276 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1277 | |
| 1278 for (int i = 0; i < 2; i++) { | |
| 1279 launcher_controller_->LockV1AppWithID(extension1_->id()); | |
| 1280 | |
| 1281 EXPECT_EQ(3, model_->item_count()); | |
| 1282 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type); | |
| 1283 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1284 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher( | |
| 1285 extension1_->id())); | |
| 1286 } | |
| 1287 | |
| 1288 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1289 | |
| 1290 EXPECT_EQ(3, model_->item_count()); | |
| 1291 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type); | |
| 1292 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1293 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1294 | |
| 1295 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1296 | |
| 1297 EXPECT_EQ(2, model_->item_count()); | |
| 1298 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1299 EXPECT_FALSE( | |
| 1300 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1301 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1302 EXPECT_FALSE( | |
| 1303 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1304 } | |
| 1305 | |
| 1306 // Check that already pinned items are not effected by locks. | |
| 1307 TEST_F(ChromeLauncherControllerTest, CheckAlreadyPinnedLockApps) { | |
| 1308 InitLauncherController(); | |
| 1309 // Model should only contain the browser shortcut and app list items. | |
| 1310 EXPECT_EQ(2, model_->item_count()); | |
| 1311 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1312 EXPECT_FALSE( | |
| 1313 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1314 | |
| 1315 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1316 launcher_controller_->PinAppWithID(extension1_->id()); | |
| 1317 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1318 | |
| 1319 EXPECT_EQ(3, model_->item_count()); | |
| 1320 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1321 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1322 EXPECT_FALSE( | |
| 1323 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1324 | |
| 1325 launcher_controller_->LockV1AppWithID(extension1_->id()); | |
| 1326 | |
| 1327 EXPECT_EQ(3, model_->item_count()); | |
| 1328 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1329 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1330 EXPECT_FALSE( | |
| 1331 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1332 | |
| 1333 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1334 | |
| 1335 EXPECT_EQ(3, model_->item_count()); | |
| 1336 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1337 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1338 EXPECT_FALSE( | |
| 1339 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1340 | |
| 1341 launcher_controller_->UnpinAppWithID(extension1_->id()); | |
| 1342 | |
| 1343 EXPECT_EQ(2, model_->item_count()); | |
| 1344 } | |
| 1345 | |
| 1346 // Check that already pinned items which get locked stay after unpinning. | |
| 1347 TEST_F(ChromeLauncherControllerTest, CheckPinnedAppsStayAfterUnlock) { | |
| 1348 InitLauncherController(); | |
| 1349 // Model should only contain the browser shortcut and app list items. | |
| 1350 EXPECT_EQ(2, model_->item_count()); | |
| 1351 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1352 EXPECT_FALSE( | |
| 1353 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1354 | |
| 1355 launcher_controller_->PinAppWithID(extension1_->id()); | |
| 1356 | |
| 1357 EXPECT_EQ(3, model_->item_count()); | |
| 1358 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1359 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1360 EXPECT_FALSE( | |
| 1361 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1362 | |
| 1363 launcher_controller_->LockV1AppWithID(extension1_->id()); | |
| 1364 | |
| 1365 EXPECT_EQ(3, model_->item_count()); | |
| 1366 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1367 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1368 EXPECT_FALSE( | |
| 1369 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1370 | |
| 1371 launcher_controller_->UnpinAppWithID(extension1_->id()); | |
| 1372 | |
| 1373 EXPECT_EQ(3, model_->item_count()); | |
| 1374 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type); | |
| 1375 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1376 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1377 | |
| 1378 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1379 | |
| 1380 EXPECT_EQ(2, model_->item_count()); | |
| 1381 } | |
| 1382 | |
| 1383 // Check that running applications wich are not pinned get properly restored | |
| 1384 // upon user change. | |
| 1385 TEST_F(ChromeLauncherControllerTest, CheckRunningAppOrder) { | |
| 1386 InitLauncherController(); | |
| 1387 // Model should only contain the browser shortcut and app list items. | |
| 1388 EXPECT_EQ(2, model_->item_count()); | |
| 1389 | |
| 1390 // Add a few running applications. | |
| 1391 launcher_controller_->LockV1AppWithID(extension1_->id()); | |
| 1392 launcher_controller_->LockV1AppWithID(extension2_->id()); | |
| 1393 launcher_controller_->LockV1AppWithID(extension3_->id()); | |
| 1394 EXPECT_EQ(5, model_->item_count()); | |
| 1395 // Note that this not only checks the order of applications but also the | |
| 1396 // running type. | |
| 1397 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus()); | |
| 1398 | |
| 1399 // Remember the current order of applications for the current user. | |
| 1400 const AccountId& current_account_id = | |
| 1401 multi_user_util::GetAccountIdFromProfile(profile()); | |
| 1402 RememberUnpinnedRunningApplicationOrder(); | |
| 1403 | |
| 1404 // Switch some items and check that restoring a user which was not yet | |
| 1405 // remembered changes nothing. | |
| 1406 model_->Move(2, 3); | |
| 1407 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus()); | |
| 1408 const AccountId second_fake_account_id( | |
| 1409 AccountId::FromUserEmail("second-fake-user@fake.com")); | |
| 1410 RestoreUnpinnedRunningApplicationOrder(second_fake_account_id); | |
| 1411 EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus()); | |
| 1412 | |
| 1413 // Restoring the stored user should however do the right thing. | |
| 1414 RestoreUnpinnedRunningApplicationOrder(current_account_id); | |
| 1415 EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus()); | |
| 1416 | |
| 1417 // Switch again some items and even delete one - making sure that the missing | |
| 1418 // item gets properly handled. | |
| 1419 model_->Move(3, 4); | |
| 1420 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1421 EXPECT_EQ("AppList, Chrome, app3, app2", GetPinnedAppStatus()); | |
| 1422 RestoreUnpinnedRunningApplicationOrder(current_account_id); | |
| 1423 EXPECT_EQ("AppList, Chrome, app2, app3", GetPinnedAppStatus()); | |
| 1424 | |
| 1425 // Check that removing more items does not crash and changes nothing. | |
| 1426 launcher_controller_->UnlockV1AppWithID(extension2_->id()); | |
| 1427 RestoreUnpinnedRunningApplicationOrder(current_account_id); | |
| 1428 EXPECT_EQ("AppList, Chrome, app3", GetPinnedAppStatus()); | |
| 1429 launcher_controller_->UnlockV1AppWithID(extension3_->id()); | |
| 1430 RestoreUnpinnedRunningApplicationOrder(current_account_id); | |
| 1431 EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus()); | |
| 1432 } | |
| 1433 | |
| 1434 TEST_F(ChromeLauncherControllerTest, ArcDeferredLaunch) { | |
| 1435 arc_test_.SetUp(profile()); | |
| 1436 | |
| 1437 launcher_controller_.reset( | |
| 1438 ChromeLauncherController::CreateInstance(profile(), model_.get())); | |
| 1439 launcher_controller_->Init(); | |
| 1440 | |
| 1441 const arc::mojom::AppInfo& app1 = arc_test_.fake_apps()[0]; | |
| 1442 const arc::mojom::AppInfo& app2 = arc_test_.fake_apps()[1]; | |
| 1443 const arc::mojom::AppInfo& app3 = arc_test_.fake_apps()[2]; | |
| 1444 const std::string arc_app_id1 = ArcAppTest::GetAppId(app1); | |
| 1445 const std::string arc_app_id2 = ArcAppTest::GetAppId(app2); | |
| 1446 const std::string arc_app_id3 = ArcAppTest::GetAppId(app3); | |
| 1447 | |
| 1448 SendListOfArcApps(); | |
| 1449 | |
| 1450 arc_test_.bridge_service()->SetStopped(); | |
| 1451 | |
| 1452 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id1)); | |
| 1453 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id2)); | |
| 1454 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id3)); | |
| 1455 | |
| 1456 arc::LaunchApp(profile(), arc_app_id1); | |
| 1457 arc::LaunchApp(profile(), arc_app_id1); | |
| 1458 arc::LaunchApp(profile(), arc_app_id2); | |
| 1459 arc::LaunchApp(profile(), arc_app_id3); | |
| 1460 arc::LaunchApp(profile(), arc_app_id3); | |
| 1461 | |
| 1462 const ash::ShelfID shelf_id_app_1 = | |
| 1463 launcher_controller_->GetShelfIDForAppID(arc_app_id1); | |
| 1464 const ash::ShelfID shelf_id_app_2 = | |
| 1465 launcher_controller_->GetShelfIDForAppID(arc_app_id2); | |
| 1466 const ash::ShelfID shelf_id_app_3 = | |
| 1467 launcher_controller_->GetShelfIDForAppID(arc_app_id3); | |
| 1468 EXPECT_NE(0, shelf_id_app_1); | |
| 1469 EXPECT_NE(0, shelf_id_app_2); | |
| 1470 EXPECT_NE(0, shelf_id_app_3); | |
| 1471 | |
| 1472 // We activated arc_app_id1 twice but expect one close for item controller | |
| 1473 // stops launching request. | |
| 1474 LauncherItemController* item_controller = | |
| 1475 launcher_controller_->GetLauncherItemController(shelf_id_app_1); | |
| 1476 ASSERT_NE(nullptr, item_controller); | |
| 1477 item_controller->Close(); | |
| 1478 base::RunLoop().RunUntilIdle(); | |
| 1479 | |
| 1480 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id1)); | |
| 1481 EXPECT_EQ(shelf_id_app_2, | |
| 1482 launcher_controller_->GetShelfIDForAppID(arc_app_id2)); | |
| 1483 EXPECT_EQ(shelf_id_app_3, | |
| 1484 launcher_controller_->GetShelfIDForAppID(arc_app_id3)); | |
| 1485 | |
| 1486 arc_test_.bridge_service()->SetReady(); | |
| 1487 SendListOfArcApps(); | |
| 1488 | |
| 1489 base::RunLoop().RunUntilIdle(); | |
| 1490 | |
| 1491 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id1)); | |
| 1492 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id2)); | |
| 1493 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id3)); | |
| 1494 | |
| 1495 ASSERT_EQ(2U, arc_test_.app_instance()->launch_requests().size()); | |
| 1496 | |
| 1497 const arc::FakeAppInstance::Request* request1 = | |
| 1498 arc_test_.app_instance()->launch_requests()[0]; | |
| 1499 const arc::FakeAppInstance::Request* request2 = | |
| 1500 arc_test_.app_instance()->launch_requests()[1]; | |
| 1501 | |
| 1502 EXPECT_TRUE((request1->IsForApp(app2) && request2->IsForApp(app3)) || | |
| 1503 (request1->IsForApp(app3) && request2->IsForApp(app2))); | |
| 1504 } | |
| 1505 | |
| 1506 TEST_F(ChromeLauncherControllerTest, ArcRunningApp) { | |
| 1507 arc_test_.SetUp(profile()); | |
| 1508 InitLauncherController(); | |
| 1509 | |
| 1510 const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]); | |
| 1511 SendListOfArcApps(); | |
| 1512 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1513 | |
| 1514 // Normal flow, create/destroy tasks. | |
| 1515 arc_test_.app_instance()->SendTaskCreated(1, arc_test_.fake_apps()[0]); | |
| 1516 EXPECT_NE(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1517 arc_test_.app_instance()->SendTaskCreated(2, arc_test_.fake_apps()[0]); | |
| 1518 EXPECT_NE(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1519 arc_test_.app_instance()->SendTaskDestroyed(1); | |
| 1520 EXPECT_NE(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1521 arc_test_.app_instance()->SendTaskDestroyed(2); | |
| 1522 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1523 | |
| 1524 // Stopping bridge removes apps. | |
| 1525 arc_test_.app_instance()->SendTaskCreated(3, arc_test_.fake_apps()[0]); | |
| 1526 EXPECT_NE(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1527 arc_test_.bridge_service()->SetStopped(); | |
| 1528 base::RunLoop().RunUntilIdle(); | |
| 1529 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(arc_app_id)); | |
| 1530 } | |
| 1531 | |
| 1532 // Validate that Arc app is pinned correctly and pin is removed automatically | |
| 1533 // once app is uninstalled. | |
| 1534 TEST_F(ChromeLauncherControllerTest, ArcAppPin) { | |
| 1535 arc_test_.SetUp(profile()); | |
| 1536 InitLauncherController(); | |
| 1537 | |
| 1538 const std::string arc_app_id = ArcAppTest::GetAppId(arc_test_.fake_apps()[0]); | |
| 1539 | |
| 1540 SendListOfArcApps(); | |
| 1541 extension_service_->AddExtension(extension1_.get()); | |
| 1542 extension_service_->AddExtension(extension2_.get()); | |
| 1543 | |
| 1544 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1545 EXPECT_FALSE(launcher_controller_->IsAppPinned(arc_app_id)); | |
| 1546 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1547 | |
| 1548 launcher_controller_->PinAppWithID(extension1_->id()); | |
| 1549 launcher_controller_->PinAppWithID(arc_app_id); | |
| 1550 launcher_controller_->PinAppWithID(extension2_->id()); | |
| 1551 | |
| 1552 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1553 EXPECT_TRUE(launcher_controller_->IsAppPinned(arc_app_id)); | |
| 1554 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 1555 | |
| 1556 EXPECT_EQ("AppList, Chrome, App1, Fake App 0, App2", GetPinnedAppStatus()); | |
| 1557 UninstallArcApps(); | |
| 1558 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1559 SendListOfArcApps(); | |
| 1560 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1561 | |
| 1562 // Disable/Enable Arc should persist pin state. | |
| 1563 launcher_controller_->PinAppWithID(arc_app_id); | |
| 1564 EXPECT_EQ("AppList, Chrome, App1, App2, Fake App 0", GetPinnedAppStatus()); | |
| 1565 arc::ArcAuthService::Get()->Shutdown(); | |
| 1566 EXPECT_EQ("AppList, Chrome, App1, App2, Fake App 0", GetPinnedAppStatus()); | |
| 1567 arc::ArcAuthService::Get()->OnPrimaryUserProfilePrepared(profile()); | |
| 1568 EXPECT_EQ("AppList, Chrome, App1, App2, Fake App 0", GetPinnedAppStatus()); | |
| 1569 | |
| 1570 // Opt-Out/Opt-In remove item from the shelf. | |
| 1571 EnableArc(false); | |
| 1572 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1573 EnableArc(true); | |
| 1574 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1575 SendListOfArcApps(); | |
| 1576 EXPECT_EQ("AppList, Chrome, App1, App2", GetPinnedAppStatus()); | |
| 1577 } | |
| 1578 | |
| 1579 // Check that with multi profile V1 apps are properly added / removed from the | |
| 1580 // shelf. | |
| 1581 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 1582 V1AppUpdateOnUserSwitch) { | |
| 1583 // Create a browser item in the LauncherController. | |
| 1584 InitLauncherController(); | |
| 1585 EXPECT_EQ(2, model_->item_count()); | |
| 1586 { | |
| 1587 // Create a "windowed gmail app". | |
| 1588 std::unique_ptr<V1App> v1_app( | |
| 1589 CreateRunningV1App(profile(), extension_misc::kGmailAppId, gmail_url)); | |
| 1590 EXPECT_EQ(3, model_->item_count()); | |
| 1591 | |
| 1592 // After switching to a second user the item should be gone. | |
| 1593 std::string user2 = "user2"; | |
| 1594 TestingProfile* profile2 = CreateMultiUserProfile(user2); | |
| 1595 const AccountId account_id2( | |
| 1596 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 1597 const AccountId account_id( | |
| 1598 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 1599 SwitchActiveUser(account_id2); | |
| 1600 EXPECT_EQ(2, model_->item_count()); | |
| 1601 | |
| 1602 // After switching back the item should be back. | |
| 1603 SwitchActiveUser(account_id); | |
| 1604 EXPECT_EQ(3, model_->item_count()); | |
| 1605 // Note we destroy now the gmail app with the closure end. | |
| 1606 } | |
| 1607 EXPECT_EQ(2, model_->item_count()); | |
| 1608 } | |
| 1609 | |
| 1610 // Check edge cases with multi profile V1 apps in the shelf. | |
| 1611 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 1612 V1AppUpdateOnUserSwitchEdgecases) { | |
| 1613 // Create a browser item in the LauncherController. | |
| 1614 InitLauncherController(); | |
| 1615 | |
| 1616 // First test: Create an app when the user is not active. | |
| 1617 std::string user2 = "user2"; | |
| 1618 TestingProfile* profile2 = CreateMultiUserProfile(user2); | |
| 1619 const AccountId account_id2( | |
| 1620 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 1621 const AccountId account_id( | |
| 1622 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 1623 { | |
| 1624 // Create a "windowed gmail app". | |
| 1625 std::unique_ptr<V1App> v1_app( | |
| 1626 CreateRunningV1App(profile2, extension_misc::kGmailAppId, gmail_url)); | |
| 1627 EXPECT_EQ(2, model_->item_count()); | |
| 1628 | |
| 1629 // However - switching to the user should show it. | |
| 1630 SwitchActiveUser(account_id2); | |
| 1631 EXPECT_EQ(3, model_->item_count()); | |
| 1632 | |
| 1633 // Second test: Remove the app when the user is not active and see that it | |
| 1634 // works. | |
| 1635 SwitchActiveUser(account_id); | |
| 1636 EXPECT_EQ(2, model_->item_count()); | |
| 1637 // Note: the closure ends and the browser will go away. | |
| 1638 } | |
| 1639 EXPECT_EQ(2, model_->item_count()); | |
| 1640 SwitchActiveUser(account_id2); | |
| 1641 EXPECT_EQ(2, model_->item_count()); | |
| 1642 SwitchActiveUser(account_id); | |
| 1643 EXPECT_EQ(2, model_->item_count()); | |
| 1644 } | |
| 1645 | |
| 1646 // Check edge case where a visiting V1 app gets closed (crbug.com/321374). | |
| 1647 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 1648 V1CloseOnVisitingDesktop) { | |
| 1649 // Create a browser item in the LauncherController. | |
| 1650 InitLauncherController(); | |
| 1651 | |
| 1652 chrome::MultiUserWindowManager* manager = | |
| 1653 chrome::MultiUserWindowManager::GetInstance(); | |
| 1654 | |
| 1655 // First create an app when the user is active. | |
| 1656 std::string user2 = "user2"; | |
| 1657 TestingProfile* profile2 = CreateMultiUserProfile(user2); | |
| 1658 const AccountId account_id( | |
| 1659 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 1660 const AccountId account_id2( | |
| 1661 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 1662 { | |
| 1663 // Create a "windowed gmail app". | |
| 1664 std::unique_ptr<V1App> v1_app(CreateRunningV1App( | |
| 1665 profile(), extension_misc::kGmailAppId, kGmailLaunchURL)); | |
| 1666 EXPECT_EQ(3, model_->item_count()); | |
| 1667 | |
| 1668 // Transfer the app to the other screen and switch users. | |
| 1669 manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(), | |
| 1670 account_id2); | |
| 1671 EXPECT_EQ(3, model_->item_count()); | |
| 1672 SwitchActiveUser(account_id2); | |
| 1673 EXPECT_EQ(2, model_->item_count()); | |
| 1674 } | |
| 1675 // After the app was destroyed, switch back. (which caused already a crash). | |
| 1676 SwitchActiveUser(account_id); | |
| 1677 | |
| 1678 // Create the same app again - which was also causing the crash. | |
| 1679 EXPECT_EQ(2, model_->item_count()); | |
| 1680 { | |
| 1681 // Create a "windowed gmail app". | |
| 1682 std::unique_ptr<V1App> v1_app(CreateRunningV1App( | |
| 1683 profile(), extension_misc::kGmailAppId, kGmailLaunchURL)); | |
| 1684 EXPECT_EQ(3, model_->item_count()); | |
| 1685 } | |
| 1686 SwitchActiveUser(account_id2); | |
| 1687 EXPECT_EQ(2, model_->item_count()); | |
| 1688 } | |
| 1689 | |
| 1690 // Check edge cases with multi profile V1 apps in the shelf. | |
| 1691 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 1692 V1AppUpdateOnUserSwitchEdgecases2) { | |
| 1693 // Create a browser item in the LauncherController. | |
| 1694 InitLauncherController(); | |
| 1695 SetLauncherControllerHelper(new TestLauncherControllerHelper); | |
| 1696 | |
| 1697 // First test: Create an app when the user is not active. | |
| 1698 std::string user2 = "user2"; | |
| 1699 TestingProfile* profile2 = CreateMultiUserProfile(user2); | |
| 1700 const AccountId account_id( | |
| 1701 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 1702 const AccountId account_id2( | |
| 1703 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 1704 SwitchActiveUser(account_id2); | |
| 1705 { | |
| 1706 // Create a "windowed gmail app". | |
| 1707 std::unique_ptr<V1App> v1_app( | |
| 1708 CreateRunningV1App(profile(), extension_misc::kGmailAppId, gmail_url)); | |
| 1709 EXPECT_EQ(2, model_->item_count()); | |
| 1710 | |
| 1711 // However - switching to the user should show it. | |
| 1712 SwitchActiveUser(account_id); | |
| 1713 EXPECT_EQ(3, model_->item_count()); | |
| 1714 | |
| 1715 // Second test: Remove the app when the user is not active and see that it | |
| 1716 // works. | |
| 1717 SwitchActiveUser(account_id2); | |
| 1718 EXPECT_EQ(2, model_->item_count()); | |
| 1719 v1_app.reset(); | |
| 1720 } | |
| 1721 EXPECT_EQ(2, model_->item_count()); | |
| 1722 SwitchActiveUser(account_id); | |
| 1723 EXPECT_EQ(2, model_->item_count()); | |
| 1724 SwitchActiveUser(account_id2); | |
| 1725 EXPECT_EQ(2, model_->item_count()); | |
| 1726 } | |
| 1727 | |
| 1728 // Check that activating an item which is on another user's desktop, will bring | |
| 1729 // it back. | |
| 1730 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 1731 TestLauncherActivationPullsBackWindow) { | |
| 1732 // Create a browser item in the LauncherController. | |
| 1733 InitLauncherController(); | |
| 1734 chrome::MultiUserWindowManager* manager = | |
| 1735 chrome::MultiUserWindowManager::GetInstance(); | |
| 1736 | |
| 1737 // Create a second test profile. The first is the one in profile() created in | |
| 1738 // BrowserWithTestWindowTest::SetUp(). | |
| 1739 // No need to add the profiles to the MultiUserWindowManager here. | |
| 1740 // CreateMultiUserProfile() already does that. | |
| 1741 TestingProfile* profile2 = CreateMultiUserProfile("user2"); | |
| 1742 const AccountId current_user = | |
| 1743 multi_user_util::GetAccountIdFromProfile(profile()); | |
| 1744 | |
| 1745 // Create a browser window with a native window for the current user. | |
| 1746 Browser::CreateParams params(profile()); | |
| 1747 std::unique_ptr<Browser> browser( | |
| 1748 chrome::CreateBrowserWithAuraTestWindowForParams(nullptr, ¶ms)); | |
| 1749 BrowserWindow* browser_window = browser->window(); | |
| 1750 aura::Window* window = browser_window->GetNativeWindow(); | |
| 1751 manager->SetWindowOwner(window, current_user); | |
| 1752 | |
| 1753 // Check that an activation of the window on its owner's desktop does not | |
| 1754 // change the visibility to another user. | |
| 1755 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false); | |
| 1756 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user)); | |
| 1757 | |
| 1758 // Transfer the window to another user's desktop and check that activating it | |
| 1759 // does pull it back to that user. | |
| 1760 manager->ShowWindowForUser( | |
| 1761 window, multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 1762 EXPECT_FALSE(manager->IsWindowOnDesktopOfUser(window, current_user)); | |
| 1763 launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false); | |
| 1764 EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user)); | |
| 1765 } | |
| 1766 | |
| 1767 // Check that lock -> pin -> unlock -> unpin does properly transition. | |
| 1768 TEST_F(ChromeLauncherControllerTest, CheckLockPinUnlockUnpin) { | |
| 1769 InitLauncherController(); | |
| 1770 // Model should only contain the browser shortcut and app list items. | |
| 1771 EXPECT_EQ(2, model_->item_count()); | |
| 1772 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1773 EXPECT_FALSE( | |
| 1774 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1775 | |
| 1776 launcher_controller_->LockV1AppWithID(extension1_->id()); | |
| 1777 | |
| 1778 EXPECT_EQ(3, model_->item_count()); | |
| 1779 EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[2].type); | |
| 1780 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1781 EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1782 | |
| 1783 launcher_controller_->PinAppWithID(extension1_->id()); | |
| 1784 | |
| 1785 EXPECT_EQ(3, model_->item_count()); | |
| 1786 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1787 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1788 EXPECT_FALSE( | |
| 1789 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1790 | |
| 1791 launcher_controller_->UnlockV1AppWithID(extension1_->id()); | |
| 1792 | |
| 1793 EXPECT_EQ(3, model_->item_count()); | |
| 1794 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 1795 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 1796 EXPECT_FALSE( | |
| 1797 launcher_controller_->IsWindowedAppInLauncher(extension1_->id())); | |
| 1798 | |
| 1799 launcher_controller_->UnpinAppWithID(extension1_->id()); | |
| 1800 | |
| 1801 EXPECT_EQ(2, model_->item_count()); | |
| 1802 } | |
| 1803 | |
| 1804 // Check that a locked (windowed V1 application) will be properly converted | |
| 1805 // between locked and pinned when the order gets changed through a profile / | |
| 1806 // policy change. | |
| 1807 TEST_F(ChromeLauncherControllerTest, RestoreDefaultAndLockedAppsResyncOrder) { | |
| 1808 InitLauncherController(); | |
| 1809 base::ListValue policy_value0; | |
| 1810 InsertPrefValue(&policy_value0, 0, extension1_->id()); | |
| 1811 InsertPrefValue(&policy_value0, 1, extension3_->id()); | |
| 1812 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1813 policy_value0.DeepCopy()); | |
| 1814 // The shelf layout has always one static item at the beginning (App List). | |
| 1815 SetShelfChromeIconIndex(0); | |
| 1816 extension_service_->AddExtension(extension1_.get()); | |
| 1817 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus()); | |
| 1818 extension_service_->AddExtension(extension2_.get()); | |
| 1819 // No new app icon will be generated. | |
| 1820 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus()); | |
| 1821 // Add the app as locked app which will add it (un-pinned). | |
| 1822 launcher_controller_->LockV1AppWithID(extension2_->id()); | |
| 1823 EXPECT_EQ("AppList, Chrome, App1, app2", GetPinnedAppStatus()); | |
| 1824 extension_service_->AddExtension(extension3_.get()); | |
| 1825 EXPECT_EQ("AppList, Chrome, App1, App3, app2", GetPinnedAppStatus()); | |
| 1826 | |
| 1827 // Now request to pin all items which should convert the locked item into a | |
| 1828 // pinned item. | |
| 1829 base::ListValue policy_value1; | |
| 1830 InsertPrefValue(&policy_value1, 0, extension3_->id()); | |
| 1831 InsertPrefValue(&policy_value1, 1, extension2_->id()); | |
| 1832 InsertPrefValue(&policy_value1, 2, extension1_->id()); | |
| 1833 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1834 policy_value1.DeepCopy()); | |
| 1835 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus()); | |
| 1836 | |
| 1837 // Going back to a status where there is no requirement for app 2 to be pinned | |
| 1838 // should convert it back to locked but not pinned and state. The position | |
| 1839 // is determined by the |ShelfModel|'s weight system and since running | |
| 1840 // applications are not allowed to be mixed with shortcuts, it should show up | |
| 1841 // at the end of the list. | |
| 1842 base::ListValue policy_value2; | |
| 1843 InsertPrefValue(&policy_value2, 0, extension3_->id()); | |
| 1844 InsertPrefValue(&policy_value2, 1, extension1_->id()); | |
| 1845 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1846 policy_value2.DeepCopy()); | |
| 1847 EXPECT_EQ("AppList, Chrome, App3, App1, app2", GetPinnedAppStatus()); | |
| 1848 | |
| 1849 // Removing an item should simply close it and everything should shift. | |
| 1850 base::ListValue policy_value3; | |
| 1851 InsertPrefValue(&policy_value3, 0, extension3_->id()); | |
| 1852 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1853 policy_value3.DeepCopy()); | |
| 1854 EXPECT_EQ("AppList, Chrome, App3, app2", GetPinnedAppStatus()); | |
| 1855 } | |
| 1856 | |
| 1857 // Check that a running and not pinned V2 application will be properly converted | |
| 1858 // between locked and pinned when the order gets changed through a profile / | |
| 1859 // policy change. | |
| 1860 TEST_F(ChromeLauncherControllerTest, | |
| 1861 RestoreDefaultAndRunningV2AppsResyncOrder) { | |
| 1862 InitLauncherController(); | |
| 1863 base::ListValue policy_value0; | |
| 1864 InsertPrefValue(&policy_value0, 0, extension1_->id()); | |
| 1865 InsertPrefValue(&policy_value0, 1, extension3_->id()); | |
| 1866 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1867 policy_value0.DeepCopy()); | |
| 1868 // The shelf layout has always one static item at the beginning (app List). | |
| 1869 SetShelfChromeIconIndex(0); | |
| 1870 extension_service_->AddExtension(extension1_.get()); | |
| 1871 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus()); | |
| 1872 extension_service_->AddExtension(extension2_.get()); | |
| 1873 // No new app icon will be generated. | |
| 1874 EXPECT_EQ("AppList, Chrome, App1", GetPinnedAppStatus()); | |
| 1875 // Add the app as an unpinned but running V2 app. | |
| 1876 CreateRunningV2App(extension2_->id()); | |
| 1877 EXPECT_EQ("AppList, Chrome, App1, *app2", GetPinnedAppStatus()); | |
| 1878 extension_service_->AddExtension(extension3_.get()); | |
| 1879 EXPECT_EQ("AppList, Chrome, App1, App3, *app2", GetPinnedAppStatus()); | |
| 1880 | |
| 1881 // Now request to pin all items which should convert the locked item into a | |
| 1882 // pinned item. | |
| 1883 base::ListValue policy_value1; | |
| 1884 InsertPrefValue(&policy_value1, 0, extension3_->id()); | |
| 1885 InsertPrefValue(&policy_value1, 1, extension2_->id()); | |
| 1886 InsertPrefValue(&policy_value1, 2, extension1_->id()); | |
| 1887 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1888 policy_value1.DeepCopy()); | |
| 1889 EXPECT_EQ("AppList, Chrome, App3, App2, App1", GetPinnedAppStatus()); | |
| 1890 | |
| 1891 // Going back to a status where there is no requirement for app 2 to be pinned | |
| 1892 // should convert it back to running V2 app. Since the position is determined | |
| 1893 // by the |ShelfModel|'s weight system, it will be after last pinned item. | |
| 1894 base::ListValue policy_value2; | |
| 1895 InsertPrefValue(&policy_value2, 0, extension3_->id()); | |
| 1896 InsertPrefValue(&policy_value2, 1, extension1_->id()); | |
| 1897 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1898 policy_value2.DeepCopy()); | |
| 1899 EXPECT_EQ("AppList, Chrome, App3, App1, *app2", GetPinnedAppStatus()); | |
| 1900 | |
| 1901 // Removing an item should simply close it and everything should shift. | |
| 1902 base::ListValue policy_value3; | |
| 1903 InsertPrefValue(&policy_value3, 0, extension3_->id()); | |
| 1904 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1905 policy_value3.DeepCopy()); | |
| 1906 EXPECT_EQ("AppList, Chrome, App3, *app2", GetPinnedAppStatus()); | |
| 1907 } | |
| 1908 | |
| 1909 // Each user has a different set of applications pinned. Check that when | |
| 1910 // switching between the two users, the state gets properly set. | |
| 1911 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestore) { | |
| 1912 base::ListValue user_a; | |
| 1913 base::ListValue user_b; | |
| 1914 SetUpMultiUserScenario(&user_a, &user_b); | |
| 1915 // Show user 1. | |
| 1916 SetShelfChromeIconIndex(6); | |
| 1917 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1918 user_a.DeepCopy()); | |
| 1919 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", | |
| 1920 GetPinnedAppStatus()); | |
| 1921 | |
| 1922 // Show user 2. | |
| 1923 SetShelfChromeIconIndex(4); | |
| 1924 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1925 user_b.DeepCopy()); | |
| 1926 | |
| 1927 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus()); | |
| 1928 | |
| 1929 // Switch back to 1. | |
| 1930 SetShelfChromeIconIndex(8); | |
| 1931 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1932 user_a.DeepCopy()); | |
| 1933 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", | |
| 1934 GetPinnedAppStatus()); | |
| 1935 | |
| 1936 // Switch back to 2. | |
| 1937 SetShelfChromeIconIndex(4); | |
| 1938 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1939 user_b.DeepCopy()); | |
| 1940 EXPECT_EQ("AppList, App7, App8, Chrome", GetPinnedAppStatus()); | |
| 1941 } | |
| 1942 | |
| 1943 // Each user has a different set of applications pinned, and one user has an | |
| 1944 // application running. Check that when switching between the two users, the | |
| 1945 // state gets properly set. | |
| 1946 TEST_F(ChromeLauncherControllerTest, UserSwitchIconRestoreWithRunningV2App) { | |
| 1947 base::ListValue user_a; | |
| 1948 base::ListValue user_b; | |
| 1949 SetUpMultiUserScenario(&user_a, &user_b); | |
| 1950 | |
| 1951 // Run App1 and assume that it is a V2 app. | |
| 1952 CreateRunningV2App(extension1_->id()); | |
| 1953 | |
| 1954 // Show user 1. | |
| 1955 SetShelfChromeIconIndex(6); | |
| 1956 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1957 user_a.DeepCopy()); | |
| 1958 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", | |
| 1959 GetPinnedAppStatus()); | |
| 1960 | |
| 1961 // Show user 2. | |
| 1962 SetShelfChromeIconIndex(4); | |
| 1963 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1964 user_b.DeepCopy()); | |
| 1965 | |
| 1966 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus()); | |
| 1967 | |
| 1968 // Switch back to 1. | |
| 1969 SetShelfChromeIconIndex(8); | |
| 1970 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1971 user_a.DeepCopy()); | |
| 1972 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, App6, Chrome", | |
| 1973 GetPinnedAppStatus()); | |
| 1974 | |
| 1975 // Switch back to 2. | |
| 1976 SetShelfChromeIconIndex(4); | |
| 1977 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1978 user_b.DeepCopy()); | |
| 1979 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus()); | |
| 1980 } | |
| 1981 | |
| 1982 // Each user has a different set of applications pinned, and one user has an | |
| 1983 // application running. The chrome icon is not the last item in the list. | |
| 1984 // Check that when switching between the two users, the state gets properly set. | |
| 1985 // There was once a bug associated with this. | |
| 1986 TEST_F(ChromeLauncherControllerTest, | |
| 1987 UserSwitchIconRestoreWithRunningV2AppChromeInMiddle) { | |
| 1988 base::ListValue user_a; | |
| 1989 base::ListValue user_b; | |
| 1990 SetUpMultiUserScenario(&user_a, &user_b); | |
| 1991 | |
| 1992 // Run App1 and assume that it is a V2 app. | |
| 1993 CreateRunningV2App(extension1_->id()); | |
| 1994 | |
| 1995 // Show user 1. | |
| 1996 SetShelfChromeIconIndex(5); | |
| 1997 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 1998 user_a.DeepCopy()); | |
| 1999 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6", | |
| 2000 GetPinnedAppStatus()); | |
| 2001 | |
| 2002 // Show user 2. | |
| 2003 SetShelfChromeIconIndex(4); | |
| 2004 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2005 user_b.DeepCopy()); | |
| 2006 | |
| 2007 EXPECT_EQ("AppList, App7, App8, Chrome, *app1", GetPinnedAppStatus()); | |
| 2008 | |
| 2009 // Switch back to 1. | |
| 2010 SetShelfChromeIconIndex(5); | |
| 2011 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2012 user_a.DeepCopy()); | |
| 2013 EXPECT_EQ("AppList, App1, App2, App3, App4, App5, Chrome, App6", | |
| 2014 GetPinnedAppStatus()); | |
| 2015 } | |
| 2016 | |
| 2017 TEST_F(ChromeLauncherControllerTest, Policy) { | |
| 2018 extension_service_->AddExtension(extension1_.get()); | |
| 2019 extension_service_->AddExtension(extension3_.get()); | |
| 2020 | |
| 2021 base::ListValue policy_value; | |
| 2022 InsertPrefValue(&policy_value, 0, extension1_->id()); | |
| 2023 InsertPrefValue(&policy_value, 1, extension2_->id()); | |
| 2024 profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps, | |
| 2025 policy_value.DeepCopy()); | |
| 2026 | |
| 2027 // Only |extension1_| should get pinned. |extension2_| is specified but not | |
| 2028 // installed, and |extension3_| is part of the default set, but that shouldn't | |
| 2029 // take effect when the policy override is in place. | |
| 2030 InitLauncherController(); | |
| 2031 EXPECT_EQ(3, model_->item_count()); | |
| 2032 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 2033 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 2034 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 2035 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2036 | |
| 2037 // Installing |extension2_| should add it to the launcher. | |
| 2038 extension_service_->AddExtension(extension2_.get()); | |
| 2039 EXPECT_EQ(4, model_->item_count()); | |
| 2040 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 2041 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[3].type); | |
| 2042 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 2043 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 2044 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2045 | |
| 2046 // Removing |extension1_| from the policy should be reflected in the launcher. | |
| 2047 policy_value.Remove(0, NULL); | |
| 2048 profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps, | |
| 2049 policy_value.DeepCopy()); | |
| 2050 EXPECT_EQ(3, model_->item_count()); | |
| 2051 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 2052 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id())); | |
| 2053 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id())); | |
| 2054 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2055 } | |
| 2056 | |
| 2057 TEST_F(ChromeLauncherControllerTest, UnpinWithUninstall) { | |
| 2058 extension_service_->AddExtension(extension3_.get()); | |
| 2059 extension_service_->AddExtension(extension4_.get()); | |
| 2060 | |
| 2061 InitLauncherController(); | |
| 2062 | |
| 2063 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2064 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); | |
| 2065 | |
| 2066 extension_service_->UnloadExtension(extension3_->id(), | |
| 2067 UnloadedExtensionInfo::REASON_UNINSTALL); | |
| 2068 | |
| 2069 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2070 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id())); | |
| 2071 } | |
| 2072 | |
| 2073 TEST_F(ChromeLauncherControllerTest, PrefUpdates) { | |
| 2074 extension_service_->AddExtension(extension2_.get()); | |
| 2075 extension_service_->AddExtension(extension3_.get()); | |
| 2076 extension_service_->AddExtension(extension4_.get()); | |
| 2077 | |
| 2078 InitLauncherController(); | |
| 2079 | |
| 2080 std::vector<std::string> expected_launchers; | |
| 2081 std::vector<std::string> actual_launchers; | |
| 2082 base::ListValue pref_value; | |
| 2083 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2084 pref_value.DeepCopy()); | |
| 2085 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2086 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2087 | |
| 2088 // Unavailable extensions don't create launcher items. | |
| 2089 InsertPrefValue(&pref_value, 0, extension1_->id()); | |
| 2090 InsertPrefValue(&pref_value, 1, extension2_->id()); | |
| 2091 InsertPrefValue(&pref_value, 2, extension4_->id()); | |
| 2092 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2093 pref_value.DeepCopy()); | |
| 2094 expected_launchers.push_back(extension2_->id()); | |
| 2095 expected_launchers.push_back(extension4_->id()); | |
| 2096 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2097 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2098 | |
| 2099 // Redundant pref entries show up only once. | |
| 2100 InsertPrefValue(&pref_value, 2, extension3_->id()); | |
| 2101 InsertPrefValue(&pref_value, 2, extension3_->id()); | |
| 2102 InsertPrefValue(&pref_value, 5, extension3_->id()); | |
| 2103 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2104 pref_value.DeepCopy()); | |
| 2105 expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id()); | |
| 2106 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2107 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2108 | |
| 2109 // Order changes are reflected correctly. | |
| 2110 pref_value.Clear(); | |
| 2111 InsertPrefValue(&pref_value, 0, extension4_->id()); | |
| 2112 InsertPrefValue(&pref_value, 1, extension3_->id()); | |
| 2113 InsertPrefValue(&pref_value, 2, extension2_->id()); | |
| 2114 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2115 pref_value.DeepCopy()); | |
| 2116 std::reverse(expected_launchers.begin(), expected_launchers.end()); | |
| 2117 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2118 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2119 | |
| 2120 // Clearing works. | |
| 2121 pref_value.Clear(); | |
| 2122 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2123 pref_value.DeepCopy()); | |
| 2124 expected_launchers.clear(); | |
| 2125 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2126 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2127 } | |
| 2128 | |
| 2129 TEST_F(ChromeLauncherControllerTest, PendingInsertionOrder) { | |
| 2130 extension_service_->AddExtension(extension1_.get()); | |
| 2131 extension_service_->AddExtension(extension3_.get()); | |
| 2132 | |
| 2133 InitLauncherController(); | |
| 2134 | |
| 2135 base::ListValue pref_value; | |
| 2136 InsertPrefValue(&pref_value, 0, extension1_->id()); | |
| 2137 InsertPrefValue(&pref_value, 1, extension2_->id()); | |
| 2138 InsertPrefValue(&pref_value, 2, extension3_->id()); | |
| 2139 profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps, | |
| 2140 pref_value.DeepCopy()); | |
| 2141 | |
| 2142 std::vector<std::string> expected_launchers; | |
| 2143 expected_launchers.push_back(extension1_->id()); | |
| 2144 expected_launchers.push_back(extension3_->id()); | |
| 2145 std::vector<std::string> actual_launchers; | |
| 2146 | |
| 2147 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2148 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2149 | |
| 2150 // Install |extension2| and verify it shows up between the other two. | |
| 2151 extension_service_->AddExtension(extension2_.get()); | |
| 2152 expected_launchers.insert(expected_launchers.begin() + 1, extension2_->id()); | |
| 2153 GetAppLaunchers(launcher_controller_.get(), &actual_launchers); | |
| 2154 EXPECT_EQ(expected_launchers, actual_launchers); | |
| 2155 } | |
| 2156 | |
| 2157 // Checks the created menus and menu lists for correctness. It uses the given | |
| 2158 // |controller| to create the objects for the given |item| and checks the | |
| 2159 // found item count against the |expected_items|. The |title| list contains the | |
| 2160 // menu titles in the order of their appearance in the menu (not including the | |
| 2161 // application name). | |
| 2162 bool CheckMenuCreation(ChromeLauncherController* controller, | |
| 2163 const ash::ShelfItem& item, | |
| 2164 size_t expected_items, | |
| 2165 base::string16 title[], | |
| 2166 bool is_browser) { | |
| 2167 ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0); | |
| 2168 // A new behavior has been added: Only show menus if there is at least one | |
| 2169 // item available. | |
| 2170 if (expected_items < 1 && is_browser) { | |
| 2171 EXPECT_EQ(0u, items.size()); | |
| 2172 return items.size() == 0; | |
| 2173 } | |
| 2174 // There should be one item in there: The title. | |
| 2175 EXPECT_EQ(expected_items + 1, items.size()); | |
| 2176 EXPECT_FALSE(items[0]->IsEnabled()); | |
| 2177 for (size_t i = 0; i < expected_items; i++) { | |
| 2178 EXPECT_EQ(title[i], items[1 + i]->title()); | |
| 2179 // Check that the first real item has a leading separator. | |
| 2180 if (i == 1) | |
| 2181 EXPECT_TRUE(items[i]->HasLeadingSeparator()); | |
| 2182 else | |
| 2183 EXPECT_FALSE(items[i]->HasLeadingSeparator()); | |
| 2184 } | |
| 2185 | |
| 2186 std::unique_ptr<ash::ShelfMenuModel> menu( | |
| 2187 new LauncherApplicationMenuItemModel( | |
| 2188 controller->GetApplicationList(item, 0))); | |
| 2189 // The first element in the menu is a spacing separator. On some systems | |
| 2190 // (e.g. Windows) such things do not exist. As such we check the existence | |
| 2191 // and adjust dynamically. | |
| 2192 int first_item = menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR ? 1 : 0; | |
| 2193 int expected_menu_items = first_item + | |
| 2194 (expected_items ? (expected_items + 3) : 2); | |
| 2195 EXPECT_EQ(expected_menu_items, menu->GetItemCount()); | |
| 2196 EXPECT_FALSE(menu->IsEnabledAt(first_item)); | |
| 2197 if (expected_items) { | |
| 2198 EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, | |
| 2199 menu->GetTypeAt(first_item + 1)); | |
| 2200 } | |
| 2201 return items.size() == expected_items + 1; | |
| 2202 } | |
| 2203 | |
| 2204 // Check that browsers get reflected correctly in the launcher menu. | |
| 2205 TEST_F(ChromeLauncherControllerTest, BrowserMenuGeneration) { | |
| 2206 EXPECT_EQ(1U, chrome::GetTotalBrowserCount()); | |
| 2207 chrome::NewTab(browser()); | |
| 2208 | |
| 2209 InitLauncherController(); | |
| 2210 | |
| 2211 // Check that the browser list is empty at this time. | |
| 2212 ash::ShelfItem item_browser; | |
| 2213 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; | |
| 2214 item_browser.id = | |
| 2215 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); | |
| 2216 EXPECT_TRUE(CheckMenuCreation( | |
| 2217 launcher_controller_.get(), item_browser, 0, NULL, true)); | |
| 2218 | |
| 2219 // Now make the created browser() visible by showing its browser window. | |
| 2220 browser()->window()->Show(); | |
| 2221 base::string16 title1 = ASCIIToUTF16("Test1"); | |
| 2222 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1); | |
| 2223 base::string16 one_menu_item[] = { title1 }; | |
| 2224 | |
| 2225 EXPECT_TRUE(CheckMenuCreation( | |
| 2226 launcher_controller_.get(), item_browser, 1, one_menu_item, true)); | |
| 2227 | |
| 2228 // Create one more browser/window and check that one more was added. | |
| 2229 std::unique_ptr<Browser> browser2( | |
| 2230 CreateBrowserWithTestWindowForProfile(profile())); | |
| 2231 chrome::NewTab(browser2.get()); | |
| 2232 browser2->window()->Show(); | |
| 2233 base::string16 title2 = ASCIIToUTF16("Test2"); | |
| 2234 NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"), | |
| 2235 title2); | |
| 2236 | |
| 2237 // Check that the list contains now two entries - make furthermore sure that | |
| 2238 // the active item is the first entry. | |
| 2239 base::string16 two_menu_items[] = {title1, title2}; | |
| 2240 EXPECT_TRUE(CheckMenuCreation( | |
| 2241 launcher_controller_.get(), item_browser, 2, two_menu_items, true)); | |
| 2242 | |
| 2243 // Apparently we have to close all tabs we have. | |
| 2244 chrome::CloseTab(browser2.get()); | |
| 2245 } | |
| 2246 | |
| 2247 // Check the multi profile case where only user related browsers should show | |
| 2248 // up. | |
| 2249 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 2250 BrowserMenuGenerationTwoUsers) { | |
| 2251 // Create a browser item in the LauncherController. | |
| 2252 InitLauncherController(); | |
| 2253 | |
| 2254 ash::ShelfItem item_browser; | |
| 2255 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; | |
| 2256 item_browser.id = | |
| 2257 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); | |
| 2258 | |
| 2259 // Check that the menu is empty. | |
| 2260 chrome::NewTab(browser()); | |
| 2261 EXPECT_TRUE(CheckMenuCreation( | |
| 2262 launcher_controller_.get(), item_browser, 0, NULL, true)); | |
| 2263 | |
| 2264 // Show the created |browser()| by showing its window. | |
| 2265 browser()->window()->Show(); | |
| 2266 base::string16 title1 = ASCIIToUTF16("Test1"); | |
| 2267 NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1); | |
| 2268 base::string16 one_menu_item1[] = { title1 }; | |
| 2269 EXPECT_TRUE(CheckMenuCreation( | |
| 2270 launcher_controller_.get(), item_browser, 1, one_menu_item1, true)); | |
| 2271 | |
| 2272 // Create a browser for another user and check that it is not included in the | |
| 2273 // users running browser list. | |
| 2274 std::string user2 = "user2"; | |
| 2275 TestingProfile* profile2 = CreateMultiUserProfile(user2); | |
| 2276 const AccountId account_id2( | |
| 2277 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 2278 std::unique_ptr<Browser> browser2( | |
| 2279 CreateBrowserAndTabWithProfile(profile2, user2, "http://test2")); | |
| 2280 base::string16 one_menu_item2[] = { ASCIIToUTF16(user2) }; | |
| 2281 EXPECT_TRUE(CheckMenuCreation( | |
| 2282 launcher_controller_.get(), item_browser, 1, one_menu_item1, true)); | |
| 2283 | |
| 2284 // Switch to the other user and make sure that only that browser window gets | |
| 2285 // shown. | |
| 2286 SwitchActiveUser(account_id2); | |
| 2287 EXPECT_TRUE(CheckMenuCreation( | |
| 2288 launcher_controller_.get(), item_browser, 1, one_menu_item2, true)); | |
| 2289 | |
| 2290 // Transferred browsers of other users should not show up in the list. | |
| 2291 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( | |
| 2292 browser()->window()->GetNativeWindow(), account_id2); | |
| 2293 EXPECT_TRUE(CheckMenuCreation( | |
| 2294 launcher_controller_.get(), item_browser, 1, one_menu_item2, true)); | |
| 2295 | |
| 2296 chrome::CloseTab(browser2.get()); | |
| 2297 } | |
| 2298 | |
| 2299 // Check that V1 apps are correctly reflected in the launcher menu using the | |
| 2300 // refocus logic. | |
| 2301 // Note that the extension matching logic is tested by the extension system | |
| 2302 // and does not need a separate test here. | |
| 2303 TEST_F(ChromeLauncherControllerTest, V1AppMenuGeneration) { | |
| 2304 EXPECT_EQ(1U, chrome::GetTotalBrowserCount()); | |
| 2305 EXPECT_EQ(0, browser()->tab_strip_model()->count()); | |
| 2306 | |
| 2307 InitLauncherControllerWithBrowser(); | |
| 2308 | |
| 2309 // Model should only contain the browser shortcut and app list items. | |
| 2310 EXPECT_EQ(2, model_->item_count()); | |
| 2311 EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2312 | |
| 2313 // Installing |extension3_| adds it to the launcher. | |
| 2314 ash::ShelfID gmail_id = model_->next_id(); | |
| 2315 extension_service_->AddExtension(extension3_.get()); | |
| 2316 EXPECT_EQ(3, model_->item_count()); | |
| 2317 int gmail_index = model_->ItemIndexByID(gmail_id); | |
| 2318 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type); | |
| 2319 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2320 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url)); | |
| 2321 | |
| 2322 // Check the menu content. | |
| 2323 ash::ShelfItem item_browser; | |
| 2324 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; | |
| 2325 item_browser.id = | |
| 2326 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); | |
| 2327 | |
| 2328 ash::ShelfItem item_gmail; | |
| 2329 item_gmail.type = ash::TYPE_APP_SHORTCUT; | |
| 2330 item_gmail.id = gmail_id; | |
| 2331 EXPECT_TRUE(CheckMenuCreation( | |
| 2332 launcher_controller_.get(), item_gmail, 0, NULL, false)); | |
| 2333 | |
| 2334 // Set the gmail URL to a new tab. | |
| 2335 base::string16 title1 = ASCIIToUTF16("Test1"); | |
| 2336 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); | |
| 2337 | |
| 2338 base::string16 one_menu_item[] = { title1 }; | |
| 2339 EXPECT_TRUE(CheckMenuCreation( | |
| 2340 launcher_controller_.get(), item_gmail, 1, one_menu_item, false)); | |
| 2341 | |
| 2342 // Create one empty tab. | |
| 2343 chrome::NewTab(browser()); | |
| 2344 base::string16 title2 = ASCIIToUTF16("Test2"); | |
| 2345 NavigateAndCommitActiveTabWithTitle( | |
| 2346 browser(), | |
| 2347 GURL("https://bla"), | |
| 2348 title2); | |
| 2349 | |
| 2350 // and another one with another gmail instance. | |
| 2351 chrome::NewTab(browser()); | |
| 2352 base::string16 title3 = ASCIIToUTF16("Test3"); | |
| 2353 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3); | |
| 2354 base::string16 two_menu_items[] = {title1, title3}; | |
| 2355 EXPECT_TRUE(CheckMenuCreation( | |
| 2356 launcher_controller_.get(), item_gmail, 2, two_menu_items, false)); | |
| 2357 | |
| 2358 // Even though the item is in the V1 app list, it should also be in the | |
| 2359 // browser list. | |
| 2360 base::string16 browser_menu_item[] = {title3}; | |
| 2361 EXPECT_TRUE(CheckMenuCreation( | |
| 2362 launcher_controller_.get(), item_browser, 1, browser_menu_item, false)); | |
| 2363 | |
| 2364 // Test that closing of (all) the item(s) does work (and all menus get | |
| 2365 // updated properly). | |
| 2366 launcher_controller_->Close(item_gmail.id); | |
| 2367 | |
| 2368 EXPECT_TRUE(CheckMenuCreation( | |
| 2369 launcher_controller_.get(), item_gmail, 0, NULL, false)); | |
| 2370 base::string16 browser_menu_item2[] = { title2 }; | |
| 2371 EXPECT_TRUE(CheckMenuCreation( | |
| 2372 launcher_controller_.get(), item_browser, 1, browser_menu_item2, false)); | |
| 2373 } | |
| 2374 | |
| 2375 // Check the multi profile case where only user related apps should show up. | |
| 2376 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 2377 V1AppMenuGenerationTwoUsers) { | |
| 2378 // Create a browser item in the LauncherController. | |
| 2379 InitLauncherController(); | |
| 2380 chrome::NewTab(browser()); | |
| 2381 | |
| 2382 // Installing |extension3_| adds it to the launcher. | |
| 2383 ash::ShelfID gmail_id = model_->next_id(); | |
| 2384 extension_service_->AddExtension(extension3_.get()); | |
| 2385 EXPECT_EQ(3, model_->item_count()); | |
| 2386 int gmail_index = model_->ItemIndexByID(gmail_id); | |
| 2387 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type); | |
| 2388 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2389 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url)); | |
| 2390 | |
| 2391 // Check the menu content. | |
| 2392 ash::ShelfItem item_browser; | |
| 2393 item_browser.type = ash::TYPE_BROWSER_SHORTCUT; | |
| 2394 item_browser.id = | |
| 2395 launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); | |
| 2396 | |
| 2397 ash::ShelfItem item_gmail; | |
| 2398 item_gmail.type = ash::TYPE_APP_SHORTCUT; | |
| 2399 item_gmail.id = gmail_id; | |
| 2400 EXPECT_TRUE(CheckMenuCreation( | |
| 2401 launcher_controller_.get(), item_gmail, 0, NULL, false)); | |
| 2402 | |
| 2403 // Set the gmail URL to a new tab. | |
| 2404 base::string16 title1 = ASCIIToUTF16("Test1"); | |
| 2405 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); | |
| 2406 | |
| 2407 base::string16 one_menu_item[] = { title1 }; | |
| 2408 EXPECT_TRUE(CheckMenuCreation( | |
| 2409 launcher_controller_.get(), item_gmail, 1, one_menu_item, false)); | |
| 2410 | |
| 2411 // Create a second profile and switch to that user. | |
| 2412 std::string user2 = "user2"; | |
| 2413 TestingProfile* profile2 = CreateMultiUserProfile(user2); | |
| 2414 const AccountId account_id2( | |
| 2415 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 2416 SwitchActiveUser(account_id2); | |
| 2417 | |
| 2418 // No item should have content yet. | |
| 2419 EXPECT_TRUE(CheckMenuCreation( | |
| 2420 launcher_controller_.get(), item_browser, 0, NULL, true)); | |
| 2421 EXPECT_TRUE(CheckMenuCreation( | |
| 2422 launcher_controller_.get(), item_gmail, 0, NULL, false)); | |
| 2423 | |
| 2424 // Transfer the browser of the first user - it should still not show up. | |
| 2425 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( | |
| 2426 browser()->window()->GetNativeWindow(), account_id2); | |
| 2427 | |
| 2428 EXPECT_TRUE(CheckMenuCreation( | |
| 2429 launcher_controller_.get(), item_browser, 0, NULL, true)); | |
| 2430 EXPECT_TRUE(CheckMenuCreation( | |
| 2431 launcher_controller_.get(), item_gmail, 0, NULL, false)); | |
| 2432 } | |
| 2433 | |
| 2434 // Check that V2 applications are creating items properly in the launcher when | |
| 2435 // instantiated by the current user. | |
| 2436 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 2437 V2AppHandlingTwoUsers) { | |
| 2438 InitLauncherController(); | |
| 2439 // Create a profile for our second user (will be destroyed by the framework). | |
| 2440 TestingProfile* profile2 = CreateMultiUserProfile("user2"); | |
| 2441 const AccountId account_id( | |
| 2442 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 2443 const AccountId account_id2( | |
| 2444 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 2445 // Check that there is a browser and a app launcher. | |
| 2446 EXPECT_EQ(2, model_->item_count()); | |
| 2447 | |
| 2448 // Add a v2 app. | |
| 2449 V2App v2_app(profile(), extension1_.get()); | |
| 2450 EXPECT_EQ(3, model_->item_count()); | |
| 2451 | |
| 2452 // After switching users the item should go away. | |
| 2453 SwitchActiveUser(account_id2); | |
| 2454 EXPECT_EQ(2, model_->item_count()); | |
| 2455 | |
| 2456 // And it should come back when switching back. | |
| 2457 SwitchActiveUser(account_id); | |
| 2458 EXPECT_EQ(3, model_->item_count()); | |
| 2459 } | |
| 2460 | |
| 2461 // Check that V2 applications are creating items properly in edge cases: | |
| 2462 // a background user creates a V2 app, gets active and inactive again and then | |
| 2463 // deletes the app. | |
| 2464 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 2465 V2AppHandlingTwoUsersEdgeCases) { | |
| 2466 InitLauncherController(); | |
| 2467 // Create a profile for our second user (will be destroyed by the framework). | |
| 2468 TestingProfile* profile2 = CreateMultiUserProfile("user2"); | |
| 2469 const AccountId account_id( | |
| 2470 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 2471 const AccountId account_id2( | |
| 2472 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 2473 // Check that there is a browser and a app launcher. | |
| 2474 EXPECT_EQ(2, model_->item_count()); | |
| 2475 | |
| 2476 // Switch to an inactive user. | |
| 2477 SwitchActiveUser(account_id2); | |
| 2478 EXPECT_EQ(2, model_->item_count()); | |
| 2479 | |
| 2480 // Add the v2 app to the inactive user and check that no item was added to | |
| 2481 // the launcher. | |
| 2482 { | |
| 2483 V2App v2_app(profile(), extension1_.get()); | |
| 2484 EXPECT_EQ(2, model_->item_count()); | |
| 2485 | |
| 2486 // Switch to the primary user and check that the item is shown. | |
| 2487 SwitchActiveUser(account_id); | |
| 2488 EXPECT_EQ(3, model_->item_count()); | |
| 2489 | |
| 2490 // Switch to the second user and check that the item goes away - even if the | |
| 2491 // item gets closed. | |
| 2492 SwitchActiveUser(account_id2); | |
| 2493 EXPECT_EQ(2, model_->item_count()); | |
| 2494 } | |
| 2495 | |
| 2496 // After the application was killed there should be still 2 items. | |
| 2497 EXPECT_EQ(2, model_->item_count()); | |
| 2498 | |
| 2499 // Switching then back to the default user should not show the additional item | |
| 2500 // anymore. | |
| 2501 SwitchActiveUser(account_id); | |
| 2502 EXPECT_EQ(2, model_->item_count()); | |
| 2503 } | |
| 2504 | |
| 2505 // Check that V2 applications will be made visible on the target desktop if | |
| 2506 // another window of the same type got previously teleported there. | |
| 2507 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 2508 V2AppFollowsTeleportedWindow) { | |
| 2509 InitLauncherController(); | |
| 2510 chrome::MultiUserWindowManager* manager = | |
| 2511 chrome::MultiUserWindowManager::GetInstance(); | |
| 2512 | |
| 2513 // Create and add three users / profiles, and go to #1's desktop. | |
| 2514 TestingProfile* profile1 = CreateMultiUserProfile("user-1"); | |
| 2515 TestingProfile* profile2 = CreateMultiUserProfile("user-2"); | |
| 2516 TestingProfile* profile3 = CreateMultiUserProfile("user-3"); | |
| 2517 const AccountId account_id1( | |
| 2518 multi_user_util::GetAccountIdFromProfile(profile1)); | |
| 2519 const AccountId account_id2( | |
| 2520 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 2521 const AccountId account_id3( | |
| 2522 multi_user_util::GetAccountIdFromProfile(profile3)); | |
| 2523 SwitchActiveUser(account_id1); | |
| 2524 | |
| 2525 // A v2 app for user #1 should be shown first and get hidden when switching to | |
| 2526 // desktop #2. | |
| 2527 V2App v2_app_1(profile1, extension1_.get()); | |
| 2528 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2529 SwitchActiveUser(account_id2); | |
| 2530 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2531 | |
| 2532 // Add a v2 app for user #1 while on desktop #2 should not be shown. | |
| 2533 V2App v2_app_2(profile1, extension1_.get()); | |
| 2534 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2535 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible()); | |
| 2536 | |
| 2537 // Teleport the app from user #1 to the desktop #2 should show it. | |
| 2538 manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(), account_id2); | |
| 2539 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2540 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible()); | |
| 2541 | |
| 2542 // Creating a new application for user #1 on desktop #2 should teleport it | |
| 2543 // there automatically. | |
| 2544 V2App v2_app_3(profile1, extension1_.get()); | |
| 2545 EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2546 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible()); | |
| 2547 EXPECT_TRUE(v2_app_3.window()->GetNativeWindow()->IsVisible()); | |
| 2548 | |
| 2549 // Switching back to desktop#1 and creating an app for user #1 should move | |
| 2550 // the app on desktop #1. | |
| 2551 SwitchActiveUser(account_id1); | |
| 2552 V2App v2_app_4(profile1, extension1_.get()); | |
| 2553 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2554 EXPECT_TRUE(v2_app_2.window()->GetNativeWindow()->IsVisible()); | |
| 2555 EXPECT_FALSE(v2_app_3.window()->GetNativeWindow()->IsVisible()); | |
| 2556 EXPECT_TRUE(v2_app_4.window()->GetNativeWindow()->IsVisible()); | |
| 2557 | |
| 2558 // Switching to desktop #3 and create an app for user #1 there should land on | |
| 2559 // his own desktop (#1). | |
| 2560 SwitchActiveUser(account_id3); | |
| 2561 V2App v2_app_5(profile1, extension1_.get()); | |
| 2562 EXPECT_FALSE(v2_app_5.window()->GetNativeWindow()->IsVisible()); | |
| 2563 SwitchActiveUser(account_id1); | |
| 2564 EXPECT_TRUE(v2_app_5.window()->GetNativeWindow()->IsVisible()); | |
| 2565 | |
| 2566 // Switching to desktop #2, hiding the app window and creating an app should | |
| 2567 // teleport there automatically. | |
| 2568 SwitchActiveUser(account_id2); | |
| 2569 v2_app_1.window()->Hide(); | |
| 2570 V2App v2_app_6(profile1, extension1_.get()); | |
| 2571 EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible()); | |
| 2572 EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible()); | |
| 2573 EXPECT_TRUE(v2_app_6.window()->GetNativeWindow()->IsVisible()); | |
| 2574 } | |
| 2575 | |
| 2576 // Check that V2 applications hide correctly on the shelf when the app window | |
| 2577 // is hidden. | |
| 2578 TEST_F(MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest, | |
| 2579 V2AppHiddenWindows) { | |
| 2580 InitLauncherController(); | |
| 2581 | |
| 2582 TestingProfile* profile2 = CreateMultiUserProfile("user-2"); | |
| 2583 const AccountId account_id( | |
| 2584 multi_user_util::GetAccountIdFromProfile(profile())); | |
| 2585 const AccountId account_id2( | |
| 2586 multi_user_util::GetAccountIdFromProfile(profile2)); | |
| 2587 SwitchActiveUser(account_id); | |
| 2588 EXPECT_EQ(2, model_->item_count()); | |
| 2589 | |
| 2590 V2App v2_app_1(profile(), extension1_.get()); | |
| 2591 EXPECT_EQ(3, model_->item_count()); | |
| 2592 { | |
| 2593 // Hide and show the app. | |
| 2594 v2_app_1.window()->Hide(); | |
| 2595 EXPECT_EQ(2, model_->item_count()); | |
| 2596 | |
| 2597 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE); | |
| 2598 EXPECT_EQ(3, model_->item_count()); | |
| 2599 } | |
| 2600 { | |
| 2601 // Switch user, hide and show the app and switch back. | |
| 2602 SwitchActiveUser(account_id2); | |
| 2603 EXPECT_EQ(2, model_->item_count()); | |
| 2604 | |
| 2605 v2_app_1.window()->Hide(); | |
| 2606 EXPECT_EQ(2, model_->item_count()); | |
| 2607 | |
| 2608 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE); | |
| 2609 EXPECT_EQ(2, model_->item_count()); | |
| 2610 | |
| 2611 SwitchActiveUser(account_id); | |
| 2612 EXPECT_EQ(3, model_->item_count()); | |
| 2613 } | |
| 2614 { | |
| 2615 // Switch user, hide the app, switch back and then show it again. | |
| 2616 SwitchActiveUser(account_id2); | |
| 2617 EXPECT_EQ(2, model_->item_count()); | |
| 2618 | |
| 2619 v2_app_1.window()->Hide(); | |
| 2620 EXPECT_EQ(2, model_->item_count()); | |
| 2621 | |
| 2622 SwitchActiveUser(account_id); | |
| 2623 EXPECT_EQ(2, model_->item_count()); | |
| 2624 | |
| 2625 v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE); | |
| 2626 EXPECT_EQ(3, model_->item_count()); | |
| 2627 } | |
| 2628 { | |
| 2629 // Create a second app, hide and show it and then hide both apps. | |
| 2630 V2App v2_app_2(profile(), extension1_.get()); | |
| 2631 EXPECT_EQ(3, model_->item_count()); | |
| 2632 | |
| 2633 v2_app_2.window()->Hide(); | |
| 2634 EXPECT_EQ(3, model_->item_count()); | |
| 2635 | |
| 2636 v2_app_2.window()->Show(extensions::AppWindow::SHOW_ACTIVE); | |
| 2637 EXPECT_EQ(3, model_->item_count()); | |
| 2638 | |
| 2639 v2_app_1.window()->Hide(); | |
| 2640 v2_app_2.window()->Hide(); | |
| 2641 EXPECT_EQ(2, model_->item_count()); | |
| 2642 } | |
| 2643 } | |
| 2644 | |
| 2645 // Checks that the generated menu list properly activates items. | |
| 2646 TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) { | |
| 2647 InitLauncherControllerWithBrowser(); | |
| 2648 | |
| 2649 // Add |extension3_| to the launcher and add two items. | |
| 2650 GURL gmail = GURL("https://mail.google.com/mail/u"); | |
| 2651 ash::ShelfID gmail_id = model_->next_id(); | |
| 2652 extension_service_->AddExtension(extension3_.get()); | |
| 2653 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url)); | |
| 2654 base::string16 title1 = ASCIIToUTF16("Test1"); | |
| 2655 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); | |
| 2656 chrome::NewTab(browser()); | |
| 2657 base::string16 title2 = ASCIIToUTF16("Test2"); | |
| 2658 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2); | |
| 2659 | |
| 2660 // Check that the menu is properly set. | |
| 2661 ash::ShelfItem item_gmail; | |
| 2662 item_gmail.type = ash::TYPE_APP_SHORTCUT; | |
| 2663 item_gmail.id = gmail_id; | |
| 2664 base::string16 two_menu_items[] = {title1, title2}; | |
| 2665 EXPECT_TRUE(CheckMenuCreation( | |
| 2666 launcher_controller_.get(), item_gmail, 2, two_menu_items, false)); | |
| 2667 EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); | |
| 2668 // Execute the second item in the list (which shouldn't do anything since that | |
| 2669 // item is per definition already the active tab). | |
| 2670 { | |
| 2671 std::unique_ptr<ash::ShelfMenuModel> menu( | |
| 2672 new LauncherApplicationMenuItemModel( | |
| 2673 launcher_controller_->GetApplicationList(item_gmail, 0))); | |
| 2674 // The first element in the menu is a spacing separator. On some systems | |
| 2675 // (e.g. Windows) such things do not exist. As such we check the existence | |
| 2676 // and adjust dynamically. | |
| 2677 int first_item = | |
| 2678 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0; | |
| 2679 menu->ActivatedAt(first_item + 3); | |
| 2680 } | |
| 2681 EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); | |
| 2682 | |
| 2683 // Execute the first item. | |
| 2684 { | |
| 2685 std::unique_ptr<ash::ShelfMenuModel> menu( | |
| 2686 new LauncherApplicationMenuItemModel( | |
| 2687 launcher_controller_->GetApplicationList(item_gmail, 0))); | |
| 2688 int first_item = | |
| 2689 (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0; | |
| 2690 menu->ActivatedAt(first_item + 2); | |
| 2691 } | |
| 2692 // Now the active tab should be the second item. | |
| 2693 EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); | |
| 2694 } | |
| 2695 | |
| 2696 // Checks that the generated menu list properly deletes items. | |
| 2697 TEST_F(ChromeLauncherControllerTest, V1AppMenuDeletionExecution) { | |
| 2698 InitLauncherControllerWithBrowser(); | |
| 2699 | |
| 2700 // Add |extension3_| to the launcher and add two items. | |
| 2701 GURL gmail = GURL("https://mail.google.com/mail/u"); | |
| 2702 ash::ShelfID gmail_id = model_->next_id(); | |
| 2703 extension_service_->AddExtension(extension3_.get()); | |
| 2704 launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url)); | |
| 2705 base::string16 title1 = ASCIIToUTF16("Test1"); | |
| 2706 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); | |
| 2707 chrome::NewTab(browser()); | |
| 2708 base::string16 title2 = ASCIIToUTF16("Test2"); | |
| 2709 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2); | |
| 2710 | |
| 2711 // Check that the menu is properly set. | |
| 2712 ash::ShelfItem item_gmail; | |
| 2713 item_gmail.type = ash::TYPE_APP_SHORTCUT; | |
| 2714 item_gmail.id = gmail_id; | |
| 2715 base::string16 two_menu_items[] = {title1, title2}; | |
| 2716 EXPECT_TRUE(CheckMenuCreation( | |
| 2717 launcher_controller_.get(), item_gmail, 2, two_menu_items, false)); | |
| 2718 | |
| 2719 int tabs = browser()->tab_strip_model()->count(); | |
| 2720 // Activate the proper tab through the menu item. | |
| 2721 { | |
| 2722 ChromeLauncherAppMenuItems items = | |
| 2723 launcher_controller_->GetApplicationList(item_gmail, 0); | |
| 2724 items[1]->Execute(0); | |
| 2725 EXPECT_EQ(tabs, browser()->tab_strip_model()->count()); | |
| 2726 } | |
| 2727 | |
| 2728 // Delete one tab through the menu item. | |
| 2729 { | |
| 2730 ChromeLauncherAppMenuItems items = | |
| 2731 launcher_controller_->GetApplicationList(item_gmail, 0); | |
| 2732 items[1]->Execute(ui::EF_SHIFT_DOWN); | |
| 2733 EXPECT_EQ(--tabs, browser()->tab_strip_model()->count()); | |
| 2734 } | |
| 2735 } | |
| 2736 | |
| 2737 // Tests that panels create launcher items correctly | |
| 2738 TEST_F(ChromeLauncherControllerTest, AppPanels) { | |
| 2739 InitLauncherControllerWithBrowser(); | |
| 2740 // App list and Browser shortcut ShelfItems are added. | |
| 2741 EXPECT_EQ(2, model_observer_->added()); | |
| 2742 EXPECT_EQ(1, model_observer_->changed()); | |
| 2743 | |
| 2744 const std::string app_id = extension1_->id(); | |
| 2745 // app_icon_loader is owned by ChromeLauncherController. | |
| 2746 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl(); | |
| 2747 app_icon_loader->AddSupportedApp(app_id); | |
| 2748 SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader)); | |
| 2749 | |
| 2750 // Test adding an app panel | |
| 2751 AppWindowLauncherItemController* app_panel_controller = | |
| 2752 new ExtensionAppWindowLauncherItemController( | |
| 2753 LauncherItemController::TYPE_APP_PANEL, "id", app_id, | |
| 2754 launcher_controller_.get()); | |
| 2755 ash::ShelfID shelf_id1 = launcher_controller_->CreateAppLauncherItem( | |
| 2756 app_panel_controller, app_id, ash::STATUS_RUNNING); | |
| 2757 int panel_index = model_observer_->last_index(); | |
| 2758 EXPECT_EQ(3, model_observer_->added()); | |
| 2759 EXPECT_EQ(1, model_observer_->changed()); | |
| 2760 EXPECT_EQ(1, app_icon_loader->fetch_count()); | |
| 2761 model_observer_->clear_counts(); | |
| 2762 | |
| 2763 // App panels should have a separate identifier than the app id | |
| 2764 EXPECT_EQ(0, launcher_controller_->GetShelfIDForAppID(app_id)); | |
| 2765 | |
| 2766 // Setting the app image image should not change the panel if it set its icon | |
| 2767 app_panel_controller->set_image_set_by_controller(true); | |
| 2768 gfx::ImageSkia image; | |
| 2769 launcher_controller_->OnAppImageUpdated(app_id, image); | |
| 2770 EXPECT_EQ(0, model_observer_->changed()); | |
| 2771 model_observer_->clear_counts(); | |
| 2772 | |
| 2773 // Add a second app panel and verify that it get the same index as the first | |
| 2774 // one had, being added to the left of the existing panel. | |
| 2775 AppWindowLauncherItemController* app_panel_controller2 = | |
| 2776 new ExtensionAppWindowLauncherItemController( | |
| 2777 LauncherItemController::TYPE_APP_PANEL, "id", app_id, | |
| 2778 launcher_controller_.get()); | |
| 2779 | |
| 2780 ash::ShelfID shelf_id2 = launcher_controller_->CreateAppLauncherItem( | |
| 2781 app_panel_controller2, app_id, ash::STATUS_RUNNING); | |
| 2782 EXPECT_EQ(panel_index, model_observer_->last_index()); | |
| 2783 EXPECT_EQ(1, model_observer_->added()); | |
| 2784 model_observer_->clear_counts(); | |
| 2785 | |
| 2786 launcher_controller_->CloseLauncherItem(shelf_id2); | |
| 2787 launcher_controller_->CloseLauncherItem(shelf_id1); | |
| 2788 EXPECT_EQ(2, model_observer_->removed()); | |
| 2789 } | |
| 2790 | |
| 2791 // Tests that the Gmail extension matches more then the app itself claims with | |
| 2792 // the manifest file. | |
| 2793 TEST_F(ChromeLauncherControllerTest, GmailMatching) { | |
| 2794 InitLauncherControllerWithBrowser(); | |
| 2795 | |
| 2796 // Create a Gmail browser tab. | |
| 2797 chrome::NewTab(browser()); | |
| 2798 base::string16 title = ASCIIToUTF16("Test"); | |
| 2799 NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title); | |
| 2800 content::WebContents* content = | |
| 2801 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 2802 | |
| 2803 // Check that the launcher controller does not recognize the running app. | |
| 2804 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content)); | |
| 2805 | |
| 2806 // Installing |extension3_| adds it to the launcher. | |
| 2807 ash::ShelfID gmail_id = model_->next_id(); | |
| 2808 extension_service_->AddExtension(extension3_.get()); | |
| 2809 EXPECT_EQ(3, model_->item_count()); | |
| 2810 int gmail_index = model_->ItemIndexByID(gmail_id); | |
| 2811 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type); | |
| 2812 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2813 | |
| 2814 // Check that it is now handled. | |
| 2815 EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content)); | |
| 2816 | |
| 2817 // Check also that the app has detected that properly. | |
| 2818 ash::ShelfItem item_gmail; | |
| 2819 item_gmail.type = ash::TYPE_APP_SHORTCUT; | |
| 2820 item_gmail.id = gmail_id; | |
| 2821 EXPECT_EQ(2U, launcher_controller_->GetApplicationList(item_gmail, 0).size()); | |
| 2822 } | |
| 2823 | |
| 2824 // Tests that the Gmail extension does not match the offline verison. | |
| 2825 TEST_F(ChromeLauncherControllerTest, GmailOfflineMatching) { | |
| 2826 InitLauncherControllerWithBrowser(); | |
| 2827 | |
| 2828 // Create a Gmail browser tab. | |
| 2829 chrome::NewTab(browser()); | |
| 2830 base::string16 title = ASCIIToUTF16("Test"); | |
| 2831 NavigateAndCommitActiveTabWithTitle(browser(), | |
| 2832 GURL(offline_gmail_url), | |
| 2833 title); | |
| 2834 content::WebContents* content = | |
| 2835 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 2836 | |
| 2837 // Installing |extension3_| adds it to the launcher. | |
| 2838 ash::ShelfID gmail_id = model_->next_id(); | |
| 2839 extension_service_->AddExtension(extension3_.get()); | |
| 2840 EXPECT_EQ(3, model_->item_count()); | |
| 2841 int gmail_index = model_->ItemIndexByID(gmail_id); | |
| 2842 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[gmail_index].type); | |
| 2843 EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id())); | |
| 2844 | |
| 2845 // The content should not be able to be handled by the app. | |
| 2846 EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content)); | |
| 2847 } | |
| 2848 | |
| 2849 // Verify that the launcher item positions are persisted and restored. | |
| 2850 TEST_F(ChromeLauncherControllerTest, PersistLauncherItemPositions) { | |
| 2851 InitLauncherController(); | |
| 2852 | |
| 2853 TestLauncherControllerHelper* helper = new TestLauncherControllerHelper; | |
| 2854 SetLauncherControllerHelper(helper); | |
| 2855 | |
| 2856 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type); | |
| 2857 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type); | |
| 2858 | |
| 2859 TabStripModel* tab_strip_model = browser()->tab_strip_model(); | |
| 2860 EXPECT_EQ(0, tab_strip_model->count()); | |
| 2861 chrome::NewTab(browser()); | |
| 2862 chrome::NewTab(browser()); | |
| 2863 EXPECT_EQ(2, tab_strip_model->count()); | |
| 2864 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1"); | |
| 2865 helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2"); | |
| 2866 | |
| 2867 EXPECT_FALSE(launcher_controller_->IsAppPinned("1")); | |
| 2868 launcher_controller_->PinAppWithID("1"); | |
| 2869 EXPECT_TRUE(launcher_controller_->IsAppPinned("1")); | |
| 2870 launcher_controller_->PinAppWithID("2"); | |
| 2871 | |
| 2872 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type); | |
| 2873 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type); | |
| 2874 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 2875 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[3].type); | |
| 2876 | |
| 2877 // Move browser shortcut item from index 1 to index 3. | |
| 2878 model_->Move(1, 3); | |
| 2879 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type); | |
| 2880 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type); | |
| 2881 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 2882 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type); | |
| 2883 | |
| 2884 SetShelfItemDelegateManager(nullptr); | |
| 2885 launcher_controller_.reset(); | |
| 2886 if (!ash::Shell::HasInstance()) { | |
| 2887 delete item_delegate_manager_; | |
| 2888 } else { | |
| 2889 // Clear already registered ShelfItemDelegate. | |
| 2890 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_); | |
| 2891 test.RemoveAllShelfItemDelegateForTest(); | |
| 2892 } | |
| 2893 model_.reset(new ash::ShelfModel); | |
| 2894 | |
| 2895 AddAppListLauncherItem(); | |
| 2896 launcher_controller_.reset( | |
| 2897 ChromeLauncherController::CreateInstance(profile(), model_.get())); | |
| 2898 helper = new TestLauncherControllerHelper; | |
| 2899 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1"); | |
| 2900 helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2"); | |
| 2901 SetLauncherControllerHelper(helper); | |
| 2902 if (!ash::Shell::HasInstance()) { | |
| 2903 item_delegate_manager_ = new ash::ShelfItemDelegateManager(model_.get()); | |
| 2904 SetShelfItemDelegateManager(item_delegate_manager_); | |
| 2905 } | |
| 2906 launcher_controller_->Init(); | |
| 2907 | |
| 2908 // Check ShelfItems are restored after resetting ChromeLauncherController. | |
| 2909 EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type); | |
| 2910 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type); | |
| 2911 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type); | |
| 2912 EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type); | |
| 2913 } | |
| 2914 | |
| 2915 // Verifies pinned apps are persisted and restored. | |
| 2916 TEST_F(ChromeLauncherControllerTest, PersistPinned) { | |
| 2917 InitLauncherControllerWithBrowser(); | |
| 2918 size_t initial_size = model_->items().size(); | |
| 2919 | |
| 2920 TabStripModel* tab_strip_model = browser()->tab_strip_model(); | |
| 2921 EXPECT_EQ(1, tab_strip_model->count()); | |
| 2922 | |
| 2923 TestLauncherControllerHelper* helper = new TestLauncherControllerHelper; | |
| 2924 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1"); | |
| 2925 SetLauncherControllerHelper(helper); | |
| 2926 | |
| 2927 // app_icon_loader is owned by ChromeLauncherController. | |
| 2928 TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl; | |
| 2929 app_icon_loader->AddSupportedApp("1"); | |
| 2930 SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader)); | |
| 2931 EXPECT_EQ(0, app_icon_loader->fetch_count()); | |
| 2932 | |
| 2933 launcher_controller_->PinAppWithID("1"); | |
| 2934 ash::ShelfID id = launcher_controller_->GetShelfIDForAppID("1"); | |
| 2935 int app_index = model_->ItemIndexByID(id); | |
| 2936 EXPECT_EQ(1, app_icon_loader->fetch_count()); | |
| 2937 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type); | |
| 2938 EXPECT_TRUE(launcher_controller_->IsAppPinned("1")); | |
| 2939 EXPECT_FALSE(launcher_controller_->IsAppPinned("0")); | |
| 2940 EXPECT_EQ(initial_size + 1, model_->items().size()); | |
| 2941 | |
| 2942 SetShelfItemDelegateManager(nullptr); | |
| 2943 launcher_controller_.reset(); | |
| 2944 if (!ash::Shell::HasInstance()) { | |
| 2945 delete item_delegate_manager_; | |
| 2946 } else { | |
| 2947 // Clear already registered ShelfItemDelegate. | |
| 2948 ash::test::ShelfItemDelegateManagerTestAPI test(item_delegate_manager_); | |
| 2949 test.RemoveAllShelfItemDelegateForTest(); | |
| 2950 } | |
| 2951 model_.reset(new ash::ShelfModel); | |
| 2952 | |
| 2953 AddAppListLauncherItem(); | |
| 2954 launcher_controller_.reset( | |
| 2955 ChromeLauncherController::CreateInstance(profile(), model_.get())); | |
| 2956 helper = new TestLauncherControllerHelper; | |
| 2957 helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1"); | |
| 2958 SetLauncherControllerHelper(helper); | |
| 2959 // app_icon_loader is owned by ChromeLauncherController. | |
| 2960 app_icon_loader = new TestAppIconLoaderImpl; | |
| 2961 app_icon_loader->AddSupportedApp("1"); | |
| 2962 SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader)); | |
| 2963 if (!ash::Shell::HasInstance()) { | |
| 2964 item_delegate_manager_ = new ash::ShelfItemDelegateManager(model_.get()); | |
| 2965 SetShelfItemDelegateManager(item_delegate_manager_); | |
| 2966 } | |
| 2967 launcher_controller_->Init(); | |
| 2968 | |
| 2969 EXPECT_EQ(1, app_icon_loader->fetch_count()); | |
| 2970 ASSERT_EQ(initial_size + 1, model_->items().size()); | |
| 2971 EXPECT_TRUE(launcher_controller_->IsAppPinned("1")); | |
| 2972 EXPECT_FALSE(launcher_controller_->IsAppPinned("0")); | |
| 2973 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type); | |
| 2974 | |
| 2975 launcher_controller_->UnpinAppWithID("1"); | |
| 2976 ASSERT_EQ(initial_size, model_->items().size()); | |
| 2977 } | |
| 2978 | |
| 2979 TEST_F(ChromeLauncherControllerTest, MultipleAppIconLoaders) { | |
| 2980 InitLauncherControllerWithBrowser(); | |
| 2981 | |
| 2982 const std::string app_id1 = extension1_->id(); | |
| 2983 const std::string app_id2 = extension2_->id(); | |
| 2984 const std::string app_id3 = extension3_->id(); | |
| 2985 // app_icon_loader1 and app_icon_loader2 are owned by | |
| 2986 // ChromeLauncherController. | |
| 2987 TestAppIconLoaderImpl* app_icon_loader1 = new TestAppIconLoaderImpl(); | |
| 2988 TestAppIconLoaderImpl* app_icon_loader2 = new TestAppIconLoaderImpl(); | |
| 2989 app_icon_loader1->AddSupportedApp(app_id1); | |
| 2990 app_icon_loader2->AddSupportedApp(app_id2); | |
| 2991 SetAppIconLoaders(std::unique_ptr<AppIconLoader>(app_icon_loader1), | |
| 2992 std::unique_ptr<AppIconLoader>(app_icon_loader2)); | |
| 2993 | |
| 2994 AppWindowLauncherItemController* app_panel_controller3 = | |
| 2995 new ExtensionAppWindowLauncherItemController( | |
| 2996 LauncherItemController::TYPE_APP_PANEL, "id", app_id3, | |
| 2997 launcher_controller_.get()); | |
| 2998 const ash::ShelfID shelfId3 = launcher_controller_->CreateAppLauncherItem( | |
| 2999 app_panel_controller3, app_id3, ash::STATUS_RUNNING); | |
| 3000 EXPECT_EQ(0, app_icon_loader1->fetch_count()); | |
| 3001 EXPECT_EQ(0, app_icon_loader1->clear_count()); | |
| 3002 EXPECT_EQ(0, app_icon_loader2->fetch_count()); | |
| 3003 EXPECT_EQ(0, app_icon_loader2->clear_count()); | |
| 3004 | |
| 3005 AppWindowLauncherItemController* app_panel_controller2 = | |
| 3006 new ExtensionAppWindowLauncherItemController( | |
| 3007 LauncherItemController::TYPE_APP_PANEL, "id", app_id2, | |
| 3008 launcher_controller_.get()); | |
| 3009 const ash::ShelfID shelfId2 = launcher_controller_->CreateAppLauncherItem( | |
| 3010 app_panel_controller2, app_id2, ash::STATUS_RUNNING); | |
| 3011 EXPECT_EQ(0, app_icon_loader1->fetch_count()); | |
| 3012 EXPECT_EQ(0, app_icon_loader1->clear_count()); | |
| 3013 EXPECT_EQ(1, app_icon_loader2->fetch_count()); | |
| 3014 EXPECT_EQ(0, app_icon_loader2->clear_count()); | |
| 3015 | |
| 3016 // Test adding an app panel | |
| 3017 AppWindowLauncherItemController* app_panel_controller1 = | |
| 3018 new ExtensionAppWindowLauncherItemController( | |
| 3019 LauncherItemController::TYPE_APP_PANEL, "id", app_id1, | |
| 3020 launcher_controller_.get()); | |
| 3021 | |
| 3022 const ash::ShelfID shelfId1 = launcher_controller_->CreateAppLauncherItem( | |
| 3023 app_panel_controller1, app_id1, ash::STATUS_RUNNING); | |
| 3024 EXPECT_EQ(1, app_icon_loader1->fetch_count()); | |
| 3025 EXPECT_EQ(0, app_icon_loader1->clear_count()); | |
| 3026 EXPECT_EQ(1, app_icon_loader2->fetch_count()); | |
| 3027 EXPECT_EQ(0, app_icon_loader2->clear_count()); | |
| 3028 | |
| 3029 launcher_controller_->CloseLauncherItem(shelfId1); | |
| 3030 EXPECT_EQ(1, app_icon_loader1->fetch_count()); | |
| 3031 EXPECT_EQ(1, app_icon_loader1->clear_count()); | |
| 3032 EXPECT_EQ(1, app_icon_loader2->fetch_count()); | |
| 3033 EXPECT_EQ(0, app_icon_loader2->clear_count()); | |
| 3034 | |
| 3035 launcher_controller_->CloseLauncherItem(shelfId2); | |
| 3036 EXPECT_EQ(1, app_icon_loader1->fetch_count()); | |
| 3037 EXPECT_EQ(1, app_icon_loader1->clear_count()); | |
| 3038 EXPECT_EQ(1, app_icon_loader2->fetch_count()); | |
| 3039 EXPECT_EQ(1, app_icon_loader2->clear_count()); | |
| 3040 | |
| 3041 launcher_controller_->CloseLauncherItem(shelfId3); | |
| 3042 EXPECT_EQ(1, app_icon_loader1->fetch_count()); | |
| 3043 EXPECT_EQ(1, app_icon_loader1->clear_count()); | |
| 3044 EXPECT_EQ(1, app_icon_loader2->fetch_count()); | |
| 3045 EXPECT_EQ(1, app_icon_loader2->clear_count()); | |
| 3046 } | |
| 3047 | |
| 3048 TEST_F(ChromeLauncherControllerTest, ArcAppPinPolicy) { | |
| 3049 arc_test_.SetUp(profile()); | |
| 3050 InitLauncherControllerWithBrowser(); | |
| 3051 | |
| 3052 arc::mojom::AppInfo appinfo; | |
| 3053 appinfo.name = "Some App"; | |
| 3054 appinfo.activity = "SomeActivity"; | |
| 3055 appinfo.package_name = "com.example.app"; | |
| 3056 | |
| 3057 ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs(); | |
| 3058 ASSERT_TRUE(prefs); | |
| 3059 | |
| 3060 // Adding app to the prefs, and check that the app is accessible by id. | |
| 3061 prefs->AddApp(appinfo); | |
| 3062 const std::string app_id = | |
| 3063 ArcAppListPrefs::GetAppId(appinfo.package_name, appinfo.activity); | |
| 3064 EXPECT_TRUE(prefs->GetApp(app_id)); | |
| 3065 | |
| 3066 // Set policy, that makes pins ARC app. Unlike native extension, for ARC app | |
| 3067 // package_name (not hash) specified as id. In this test we check that | |
| 3068 // by hash we can determine that appropriate package was set by policy. | |
| 3069 base::ListValue policy_value; | |
| 3070 InsertPrefValue(&policy_value, 0, appinfo.package_name); | |
| 3071 profile()->GetTestingPrefService()->SetManagedPref( | |
| 3072 prefs::kPolicyPinnedLauncherApps, policy_value.DeepCopy()); | |
| 3073 | |
| 3074 EXPECT_TRUE(launcher_controller_->IsAppPinned(app_id)); | |
| 3075 EXPECT_EQ(AppListControllerDelegate::PIN_FIXED, | |
| 3076 launcher_controller_->GetPinnable(app_id)); | |
| 3077 } | |
| OLD | NEW |