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