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