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