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