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