Home | History | Annotate | Download | only in shelf
      1 // Copyright (c) 2012 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 "ash/shelf/shelf_view.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "ash/ash_switches.h"
     11 #include "ash/launcher/launcher.h"
     12 #include "ash/launcher/launcher_types.h"
     13 #include "ash/root_window_controller.h"
     14 #include "ash/shelf/overflow_bubble.h"
     15 #include "ash/shelf/overflow_bubble_view.h"
     16 #include "ash/shelf/shelf_button.h"
     17 #include "ash/shelf/shelf_icon_observer.h"
     18 #include "ash/shelf/shelf_item_delegate_manager.h"
     19 #include "ash/shelf/shelf_layout_manager.h"
     20 #include "ash/shelf/shelf_model.h"
     21 #include "ash/shelf/shelf_tooltip_manager.h"
     22 #include "ash/shelf/shelf_widget.h"
     23 #include "ash/shell.h"
     24 #include "ash/shell_window_ids.h"
     25 #include "ash/test/ash_test_base.h"
     26 #include "ash/test/launcher_test_api.h"
     27 #include "ash/test/overflow_bubble_view_test_api.h"
     28 #include "ash/test/shelf_view_test_api.h"
     29 #include "ash/test/shell_test_api.h"
     30 #include "ash/test/test_shelf_delegate.h"
     31 #include "ash/test/test_shelf_item_delegate.h"
     32 #include "ash/wm/coordinate_conversion.h"
     33 #include "base/basictypes.h"
     34 #include "base/command_line.h"
     35 #include "base/compiler_specific.h"
     36 #include "base/memory/scoped_ptr.h"
     37 #include "base/strings/string_number_conversions.h"
     38 #include "grit/ash_resources.h"
     39 #include "ui/aura/root_window.h"
     40 #include "ui/aura/test/aura_test_base.h"
     41 #include "ui/aura/test/event_generator.h"
     42 #include "ui/aura/window.h"
     43 #include "ui/base/l10n/l10n_util.h"
     44 #include "ui/compositor/layer.h"
     45 #include "ui/events/event.h"
     46 #include "ui/events/event_constants.h"
     47 #include "ui/views/view_model.h"
     48 #include "ui/views/widget/widget.h"
     49 #include "ui/views/widget/widget_delegate.h"
     50 
     51 namespace ash {
     52 namespace test {
     53 
     54 ////////////////////////////////////////////////////////////////////////////////
     55 // ShelfIconObserver tests.
     56 
     57 class TestShelfIconObserver : public ShelfIconObserver {
     58  public:
     59   explicit TestShelfIconObserver(Launcher* launcher)
     60       : launcher_(launcher),
     61         change_notified_(false) {
     62     if (launcher_)
     63       launcher_->AddIconObserver(this);
     64   }
     65 
     66   virtual ~TestShelfIconObserver() {
     67     if (launcher_)
     68       launcher_->RemoveIconObserver(this);
     69   }
     70 
     71   // ShelfIconObserver implementation.
     72   virtual void OnShelfIconPositionsChanged() OVERRIDE {
     73     change_notified_ = true;
     74   }
     75 
     76   int change_notified() const { return change_notified_; }
     77   void Reset() { change_notified_ = false; }
     78 
     79  private:
     80   Launcher* launcher_;
     81   bool change_notified_;
     82 
     83   DISALLOW_COPY_AND_ASSIGN(TestShelfIconObserver);
     84 };
     85 
     86 class ShelfViewIconObserverTest : public AshTestBase {
     87  public:
     88   ShelfViewIconObserverTest() {}
     89   virtual ~ShelfViewIconObserverTest() {}
     90 
     91   virtual void SetUp() OVERRIDE {
     92     AshTestBase::SetUp();
     93     Launcher* launcher = Launcher::ForPrimaryDisplay();
     94     observer_.reset(new TestShelfIconObserver(launcher));
     95 
     96     shelf_view_test_.reset(new ShelfViewTestAPI(
     97         LauncherTestAPI(launcher).shelf_view()));
     98     shelf_view_test_->SetAnimationDuration(1);
     99   }
    100 
    101   virtual void TearDown() OVERRIDE {
    102     observer_.reset();
    103     AshTestBase::TearDown();
    104   }
    105 
    106   TestShelfIconObserver* observer() { return observer_.get(); }
    107 
    108   ShelfViewTestAPI* shelf_view_test() {
    109     return shelf_view_test_.get();
    110   }
    111 
    112   Launcher* LauncherForSecondaryDisplay() {
    113     return Launcher::ForWindow(Shell::GetAllRootWindows()[1]);
    114   }
    115 
    116  private:
    117   scoped_ptr<TestShelfIconObserver> observer_;
    118   scoped_ptr<ShelfViewTestAPI> shelf_view_test_;
    119 
    120   DISALLOW_COPY_AND_ASSIGN(ShelfViewIconObserverTest);
    121 };
    122 
    123 TEST_F(ShelfViewIconObserverTest, AddRemove) {
    124   TestShelfDelegate* shelf_delegate = TestShelfDelegate::instance();
    125   ASSERT_TRUE(shelf_delegate);
    126 
    127   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    128   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    129   params.bounds = gfx::Rect(0, 0, 200, 200);
    130   params.context = CurrentContext();
    131 
    132   scoped_ptr<views::Widget> widget(new views::Widget());
    133   widget->Init(params);
    134   shelf_delegate->AddLauncherItem(widget->GetNativeWindow());
    135   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
    136   EXPECT_TRUE(observer()->change_notified());
    137   observer()->Reset();
    138 
    139   widget->Show();
    140   widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
    141   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
    142   EXPECT_TRUE(observer()->change_notified());
    143   observer()->Reset();
    144 }
    145 
    146 // Sometimes fails on trybots on win7_aura. http://crbug.com/177135
    147 #if defined(OS_WIN)
    148 #define MAYBE_AddRemoveWithMultipleDisplays \
    149     DISABLED_AddRemoveWithMultipleDisplays
    150 #else
    151 #define MAYBE_AddRemoveWithMultipleDisplays \
    152     AddRemoveWithMultipleDisplays
    153 #endif
    154 // Make sure creating/deleting an window on one displays notifies a
    155 // launcher on external display as well as one on primary.
    156 TEST_F(ShelfViewIconObserverTest, MAYBE_AddRemoveWithMultipleDisplays) {
    157   UpdateDisplay("400x400,400x400");
    158   TestShelfIconObserver second_observer(LauncherForSecondaryDisplay());
    159 
    160   TestShelfDelegate* shelf_delegate = TestShelfDelegate::instance();
    161   ASSERT_TRUE(shelf_delegate);
    162 
    163   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    164   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    165   params.bounds = gfx::Rect(0, 0, 200, 200);
    166   params.context = CurrentContext();
    167 
    168   scoped_ptr<views::Widget> widget(new views::Widget());
    169   widget->Init(params);
    170   shelf_delegate->AddLauncherItem(widget->GetNativeWindow());
    171   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
    172   EXPECT_TRUE(observer()->change_notified());
    173   EXPECT_TRUE(second_observer.change_notified());
    174   observer()->Reset();
    175   second_observer.Reset();
    176 
    177   widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
    178   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
    179   EXPECT_TRUE(observer()->change_notified());
    180   EXPECT_TRUE(second_observer.change_notified());
    181 
    182   observer()->Reset();
    183   second_observer.Reset();
    184 }
    185 
    186 TEST_F(ShelfViewIconObserverTest, BoundsChanged) {
    187   ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
    188   Launcher* launcher = Launcher::ForPrimaryDisplay();
    189   gfx::Size shelf_size =
    190       shelf->GetWindowBoundsInScreen().size();
    191   shelf_size.set_width(shelf_size.width() / 2);
    192   ASSERT_GT(shelf_size.width(), 0);
    193   launcher->SetShelfViewBounds(gfx::Rect(shelf_size));
    194   // No animation happens for ShelfView bounds change.
    195   EXPECT_TRUE(observer()->change_notified());
    196   observer()->Reset();
    197 }
    198 
    199 ////////////////////////////////////////////////////////////////////////////////
    200 // ShelfView tests.
    201 
    202 // Simple ShelfDelegate implmentation for ShelfViewTest.OverflowBubbleSize
    203 // and CheckDragAndDropFromOverflowBubbleToShelf
    204 class TestShelfDelegateForShelfView : public ShelfDelegate {
    205  public:
    206   explicit TestShelfDelegateForShelfView(ShelfModel* model)
    207       : model_(model) {}
    208   virtual ~TestShelfDelegateForShelfView() {}
    209 
    210   // ShelfDelegate overrides:
    211   virtual void OnLauncherCreated(Launcher* launcher) OVERRIDE {}
    212 
    213   virtual void OnLauncherDestroyed(Launcher* launcher) OVERRIDE {}
    214 
    215   virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) OVERRIDE {
    216     LauncherID id = 0;
    217     EXPECT_TRUE(base::StringToInt(app_id, &id));
    218     return id;
    219   }
    220 
    221   virtual const std::string& GetAppIDForLauncherID(LauncherID id) OVERRIDE {
    222     // Use |app_id_| member variable because returning a reference to local
    223     // variable is not allowed.
    224     app_id_ = base::IntToString(id);
    225     return app_id_;
    226   }
    227 
    228   virtual void PinAppWithID(const std::string& app_id) OVERRIDE {
    229   }
    230 
    231   virtual bool IsAppPinned(const std::string& app_id) OVERRIDE {
    232     // Returns true for ShelfViewTest.OverflowBubbleSize. To test ripping off in
    233     // that test, an item is already pinned state.
    234     return true;
    235   }
    236 
    237   virtual bool CanPin() const OVERRIDE {
    238     return true;
    239   }
    240 
    241   virtual void UnpinAppWithID(const std::string& app_id) OVERRIDE {
    242     LauncherID id = 0;
    243     EXPECT_TRUE(base::StringToInt(app_id, &id));
    244     ASSERT_GT(id, 0);
    245     int index = model_->ItemIndexByID(id);
    246     ASSERT_GE(index, 0);
    247 
    248     model_->RemoveItemAt(index);
    249   }
    250 
    251  private:
    252   ShelfModel* model_;
    253 
    254   // Temp member variable for returning a value. See the comment in the
    255   // GetAppIDForLauncherID().
    256   std::string app_id_;
    257 
    258   DISALLOW_COPY_AND_ASSIGN(TestShelfDelegateForShelfView);
    259 };
    260 
    261 class ShelfViewTest : public AshTestBase {
    262  public:
    263   ShelfViewTest() : model_(NULL), shelf_view_(NULL), browser_index_(1) {}
    264   virtual ~ShelfViewTest() {}
    265 
    266   virtual void SetUp() OVERRIDE {
    267     AshTestBase::SetUp();
    268     test::ShellTestApi test_api(Shell::GetInstance());
    269     model_ = test_api.shelf_model();
    270     Launcher* launcher = Launcher::ForPrimaryDisplay();
    271     shelf_view_ = test::LauncherTestAPI(launcher).shelf_view();
    272 
    273     // The bounds should be big enough for 4 buttons + overflow chevron.
    274     shelf_view_->SetBounds(0, 0, 500,
    275         internal::ShelfLayoutManager::GetPreferredShelfSize());
    276 
    277     test_api_.reset(new ShelfViewTestAPI(shelf_view_));
    278     test_api_->SetAnimationDuration(1);  // Speeds up animation for test.
    279 
    280     item_manager_ = Shell::GetInstance()->shelf_item_delegate_manager();
    281     DCHECK(item_manager_);
    282 
    283     // Add browser shortcut launcher item at index 0 for test.
    284     AddBrowserShortcut();
    285   }
    286 
    287   virtual void TearDown() OVERRIDE {
    288     test_api_.reset();
    289     AshTestBase::TearDown();
    290   }
    291 
    292  protected:
    293   void CreateAndSetShelfItemDelegateForID(LauncherID id) {
    294     scoped_ptr<ShelfItemDelegate> delegate(new TestShelfItemDelegate(NULL));
    295     item_manager_->SetShelfItemDelegate(id, delegate.Pass());
    296   }
    297 
    298   LauncherID AddBrowserShortcut() {
    299     LauncherItem browser_shortcut;
    300     browser_shortcut.type = TYPE_BROWSER_SHORTCUT;
    301 
    302     LauncherID id = model_->next_id();
    303     model_->AddAt(browser_index_, browser_shortcut);
    304     CreateAndSetShelfItemDelegateForID(id);
    305     test_api_->RunMessageLoopUntilAnimationsDone();
    306     return id;
    307   }
    308 
    309   LauncherID AddAppShortcut() {
    310     LauncherItem item;
    311     item.type = TYPE_APP_SHORTCUT;
    312     item.status = STATUS_CLOSED;
    313 
    314     LauncherID id = model_->next_id();
    315     model_->Add(item);
    316     CreateAndSetShelfItemDelegateForID(id);
    317     test_api_->RunMessageLoopUntilAnimationsDone();
    318     return id;
    319   }
    320 
    321   LauncherID AddPanel() {
    322     LauncherID id = AddPanelNoWait();
    323     test_api_->RunMessageLoopUntilAnimationsDone();
    324     return id;
    325   }
    326 
    327   LauncherID AddPlatformAppNoWait() {
    328     LauncherItem item;
    329     item.type = TYPE_PLATFORM_APP;
    330     item.status = STATUS_RUNNING;
    331 
    332     LauncherID id = model_->next_id();
    333     model_->Add(item);
    334     CreateAndSetShelfItemDelegateForID(id);
    335     return id;
    336   }
    337 
    338   LauncherID AddPanelNoWait() {
    339     LauncherItem item;
    340     item.type = TYPE_APP_PANEL;
    341     item.status = STATUS_RUNNING;
    342 
    343     LauncherID id = model_->next_id();
    344     model_->Add(item);
    345     CreateAndSetShelfItemDelegateForID(id);
    346     return id;
    347   }
    348 
    349   LauncherID AddPlatformApp() {
    350     LauncherID id = AddPlatformAppNoWait();
    351     test_api_->RunMessageLoopUntilAnimationsDone();
    352     return id;
    353   }
    354 
    355   void RemoveByID(LauncherID id) {
    356     model_->RemoveItemAt(model_->ItemIndexByID(id));
    357     test_api_->RunMessageLoopUntilAnimationsDone();
    358   }
    359 
    360   internal::ShelfButton* GetButtonByID(LauncherID id) {
    361     int index = model_->ItemIndexByID(id);
    362     return test_api_->GetButton(index);
    363   }
    364 
    365   LauncherItem GetItemByID(LauncherID id) {
    366     LauncherItems::const_iterator items = model_->ItemByID(id);
    367     return *items;
    368   }
    369 
    370   void CheckModelIDs(
    371       const std::vector<std::pair<LauncherID, views::View*> >& id_map) {
    372     size_t map_index = 0;
    373     for (size_t model_index = 0;
    374          model_index < model_->items().size();
    375          ++model_index) {
    376       LauncherItem item = model_->items()[model_index];
    377       LauncherID id = item.id;
    378       EXPECT_EQ(id_map[map_index].first, id);
    379       EXPECT_EQ(id_map[map_index].second, GetButtonByID(id));
    380       ++map_index;
    381     }
    382     ASSERT_EQ(map_index, id_map.size());
    383   }
    384 
    385   void VerifyLauncherItemBoundsAreValid() {
    386     for (int i=0;i <= test_api_->GetLastVisibleIndex(); ++i) {
    387       if (test_api_->GetButton(i)) {
    388         gfx::Rect shelf_view_bounds = shelf_view_->GetLocalBounds();
    389         gfx::Rect item_bounds = test_api_->GetBoundsByIndex(i);
    390         EXPECT_TRUE(item_bounds.x() >= 0);
    391         EXPECT_TRUE(item_bounds.y() >= 0);
    392         EXPECT_TRUE(item_bounds.right() <= shelf_view_bounds.width());
    393         EXPECT_TRUE(item_bounds.bottom() <= shelf_view_bounds.height());
    394       }
    395     }
    396   }
    397 
    398   views::View* SimulateButtonPressed(
    399       internal::ShelfButtonHost::Pointer pointer,
    400       int button_index) {
    401     internal::ShelfButtonHost* button_host = shelf_view_;
    402     views::View* button = test_api_->GetButton(button_index);
    403     ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED,
    404                                button->bounds().origin(),
    405                                button->GetBoundsInScreen().origin(), 0);
    406     button_host->PointerPressedOnButton(button, pointer, click_event);
    407     return button;
    408   }
    409 
    410   views::View* SimulateClick(internal::ShelfButtonHost::Pointer pointer,
    411                              int button_index) {
    412     internal::ShelfButtonHost* button_host = shelf_view_;
    413     views::View* button = SimulateButtonPressed(pointer, button_index);
    414     button_host->PointerReleasedOnButton(button,
    415                                          internal::ShelfButtonHost::MOUSE,
    416                                          false);
    417     return button;
    418   }
    419 
    420   views::View* SimulateDrag(internal::ShelfButtonHost::Pointer pointer,
    421                             int button_index,
    422                             int destination_index) {
    423     internal::ShelfButtonHost* button_host = shelf_view_;
    424     views::View* button = SimulateButtonPressed(pointer, button_index);
    425 
    426     // Drag.
    427     views::View* destination = test_api_->GetButton(destination_index);
    428     ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
    429                               destination->bounds().origin(),
    430                               destination->GetBoundsInScreen().origin(), 0);
    431     button_host->PointerDraggedOnButton(button, pointer, drag_event);
    432     return button;
    433   }
    434 
    435   void SetupForDragTest(
    436       std::vector<std::pair<LauncherID, views::View*> >* id_map) {
    437     // Initialize |id_map| with the automatically-created launcher buttons.
    438     for (size_t i = 0; i < model_->items().size(); ++i) {
    439       internal::ShelfButton* button = test_api_->GetButton(i);
    440       id_map->push_back(std::make_pair(model_->items()[i].id, button));
    441     }
    442     ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
    443 
    444     // Add 5 app launcher buttons for testing.
    445     for (int i = 0; i < 5; ++i) {
    446       LauncherID id = AddAppShortcut();
    447       // App Icon is located at index 0, and browser shortcut is located at
    448       // index 1. So we should start to add app shortcut at index 2.
    449       id_map->insert(id_map->begin() + (i + browser_index_ + 1),
    450                      std::make_pair(id, GetButtonByID(id)));
    451     }
    452     ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
    453   }
    454 
    455   views::View* GetTooltipAnchorView() {
    456     return shelf_view_->tooltip_manager()->anchor_;
    457   }
    458 
    459   void AddButtonsUntilOverflow() {
    460     int items_added = 0;
    461     while (!test_api_->IsOverflowButtonVisible()) {
    462       AddAppShortcut();
    463       ++items_added;
    464       ASSERT_LT(items_added, 10000);
    465     }
    466   }
    467 
    468   void ShowTooltip() {
    469     shelf_view_->tooltip_manager()->ShowInternal();
    470   }
    471 
    472   void TestDraggingAnItemFromOverflowToShelf(bool cancel) {
    473     test_api_->ShowOverflowBubble();
    474     ASSERT_TRUE(test_api_->overflow_bubble() &&
    475                 test_api_->overflow_bubble()->IsShowing());
    476 
    477     ash::test::ShelfViewTestAPI test_api_for_overflow(
    478       test_api_->overflow_bubble()->shelf_view());
    479 
    480     int total_item_count = model_->item_count();
    481 
    482     int last_visible_item_id_in_shelf =
    483         model_->items()[test_api_->GetLastVisibleIndex()].id;
    484     int second_last_visible_item_id_in_shelf =
    485         model_->items()[test_api_->GetLastVisibleIndex() - 1].id;
    486     int first_visible_item_id_in_overflow =
    487         model_->items()[test_api_for_overflow.GetFirstVisibleIndex()].id;
    488     int second_last_visible_item_id_in_overflow =
    489         model_->items()[test_api_for_overflow.GetLastVisibleIndex() - 1].id;
    490 
    491     int drag_item_index =
    492         test_api_for_overflow.GetLastVisibleIndex();
    493     LauncherID drag_item_id = model_->items()[drag_item_index].id;
    494     internal::ShelfButton* drag_button =
    495         test_api_for_overflow.GetButton(drag_item_index);
    496     gfx::Point center_point_of_drag_item =
    497         drag_button->GetBoundsInScreen().CenterPoint();
    498 
    499     aura::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow(),
    500                                          center_point_of_drag_item);
    501     // Rip an item off to OverflowBubble.
    502     generator.PressLeftButton();
    503     gfx::Point rip_off_point(center_point_of_drag_item.x(), 0);
    504     generator.MoveMouseTo(rip_off_point);
    505     test_api_for_overflow.RunMessageLoopUntilAnimationsDone();
    506     ASSERT_TRUE(test_api_for_overflow.IsRippedOffFromShelf());
    507     ASSERT_FALSE(test_api_for_overflow.DraggedItemFromOverflowToShelf());
    508 
    509     // Move a dragged item into Shelf at |drop_index|.
    510     int drop_index = 1;
    511     gfx::Point drop_point =
    512         test_api_->GetButton(drop_index)->GetBoundsInScreen().CenterPoint();
    513     int item_width = test_api_for_overflow.GetButtonSize();
    514     // To insert at |drop_index|, more smaller x-axis value of |drop_point|
    515     // should be used.
    516     gfx::Point modified_drop_point(drop_point.x() - item_width / 4,
    517                                    drop_point.y());
    518     generator.MoveMouseTo(modified_drop_point);
    519     test_api_for_overflow.RunMessageLoopUntilAnimationsDone();
    520     test_api_->RunMessageLoopUntilAnimationsDone();
    521     ASSERT_TRUE(test_api_for_overflow.IsRippedOffFromShelf());
    522     ASSERT_TRUE(test_api_for_overflow.DraggedItemFromOverflowToShelf());
    523 
    524     if (cancel)
    525       drag_button->OnMouseCaptureLost();
    526     else
    527       generator.ReleaseLeftButton();
    528 
    529     test_api_for_overflow.RunMessageLoopUntilAnimationsDone();
    530     test_api_->RunMessageLoopUntilAnimationsDone();
    531     ASSERT_FALSE(test_api_for_overflow.IsRippedOffFromShelf());
    532     ASSERT_FALSE(test_api_for_overflow.DraggedItemFromOverflowToShelf());
    533 
    534     // Compare pre-stored items' id with newly positioned items' after dragging
    535     // is canceled or finished.
    536     if (cancel) {
    537       EXPECT_EQ(model_->items()[test_api_->GetLastVisibleIndex()].id,
    538           last_visible_item_id_in_shelf);
    539       EXPECT_EQ(model_->items()[test_api_->GetLastVisibleIndex() - 1].id,
    540           second_last_visible_item_id_in_shelf);
    541       EXPECT_EQ(
    542           model_->items()[test_api_for_overflow.GetFirstVisibleIndex()].id,
    543           first_visible_item_id_in_overflow);
    544       EXPECT_EQ(
    545           model_->items()[test_api_for_overflow.GetLastVisibleIndex() - 1].id,
    546           second_last_visible_item_id_in_overflow);
    547     } else {
    548       LauncherID drop_item_id = model_->items()[drop_index].id;
    549       EXPECT_EQ(drop_item_id, drag_item_id);
    550       EXPECT_EQ(model_->item_count(), total_item_count);
    551       EXPECT_EQ(
    552           model_->items()[test_api_for_overflow.GetFirstVisibleIndex()].id,
    553           last_visible_item_id_in_shelf);
    554       EXPECT_EQ(model_->items()[test_api_->GetLastVisibleIndex()].id,
    555           second_last_visible_item_id_in_shelf);
    556       EXPECT_EQ(
    557           model_->items()[test_api_for_overflow.GetFirstVisibleIndex() + 1].id,
    558           first_visible_item_id_in_overflow);
    559       EXPECT_EQ(model_->items()[test_api_for_overflow.GetLastVisibleIndex()].id,
    560           second_last_visible_item_id_in_overflow);
    561     }
    562   }
    563 
    564   ShelfModel* model_;
    565   internal::ShelfView* shelf_view_;
    566   int browser_index_;
    567   ShelfItemDelegateManager* item_manager_;
    568 
    569   scoped_ptr<ShelfViewTestAPI> test_api_;
    570 
    571  private:
    572   DISALLOW_COPY_AND_ASSIGN(ShelfViewTest);
    573 };
    574 
    575 class ShelfViewLegacyShelfLayoutTest : public ShelfViewTest {
    576  public:
    577   ShelfViewLegacyShelfLayoutTest() : ShelfViewTest() {
    578     browser_index_ = 0;
    579   }
    580 
    581   virtual ~ShelfViewLegacyShelfLayoutTest() {}
    582 
    583   virtual void SetUp() OVERRIDE {
    584     CommandLine::ForCurrentProcess()->AppendSwitch(
    585         ash::switches::kAshDisableAlternateShelfLayout);
    586     ShelfViewTest::SetUp();
    587   }
    588 
    589  private:
    590   DISALLOW_COPY_AND_ASSIGN(ShelfViewLegacyShelfLayoutTest);
    591 };
    592 
    593 class ScopedTextDirectionChange {
    594  public:
    595   ScopedTextDirectionChange(bool is_rtl)
    596       : is_rtl_(is_rtl) {
    597     original_locale_ = l10n_util::GetApplicationLocale(std::string());
    598     if (is_rtl_)
    599       base::i18n::SetICUDefaultLocale("he");
    600     CheckTextDirectionIsCorrect();
    601   }
    602 
    603   ~ScopedTextDirectionChange() {
    604     if (is_rtl_)
    605       base::i18n::SetICUDefaultLocale(original_locale_);
    606   }
    607 
    608  private:
    609   void CheckTextDirectionIsCorrect() {
    610     ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
    611   }
    612 
    613   bool is_rtl_;
    614   std::string original_locale_;
    615 };
    616 
    617 class ShelfViewTextDirectionTest
    618     : public ShelfViewTest,
    619       public testing::WithParamInterface<bool> {
    620  public:
    621   ShelfViewTextDirectionTest() : text_direction_change_(GetParam()) {}
    622   virtual ~ShelfViewTextDirectionTest() {}
    623 
    624   virtual void SetUp() OVERRIDE {
    625     ShelfViewTest::SetUp();
    626   }
    627 
    628   virtual void TearDown() OVERRIDE {
    629     ShelfViewTest::TearDown();
    630   }
    631 
    632  private:
    633   ScopedTextDirectionChange text_direction_change_;
    634 
    635   DISALLOW_COPY_AND_ASSIGN(ShelfViewTextDirectionTest);
    636 };
    637 
    638 // Checks that the ideal item icon bounds match the view's bounds in the screen
    639 // in both LTR and RTL.
    640 TEST_P(ShelfViewTextDirectionTest, IdealBoundsOfItemIcon) {
    641   LauncherID id = AddPlatformApp();
    642   internal::ShelfButton* button = GetButtonByID(id);
    643   gfx::Rect item_bounds = button->GetBoundsInScreen();
    644   gfx::Point icon_offset = button->GetIconBounds().origin();
    645   item_bounds.Offset(icon_offset.OffsetFromOrigin());
    646   gfx::Rect ideal_bounds = shelf_view_->GetIdealBoundsOfItemIcon(id);
    647   gfx::Point screen_origin;
    648   views::View::ConvertPointToScreen(shelf_view_, &screen_origin);
    649   ideal_bounds.Offset(screen_origin.x(), screen_origin.y());
    650   EXPECT_EQ(item_bounds.x(), ideal_bounds.x());
    651   EXPECT_EQ(item_bounds.y(), ideal_bounds.y());
    652 }
    653 
    654 // Checks that shelf view contents are considered in the correct drag group.
    655 TEST_F(ShelfViewTest, EnforceDragType) {
    656   EXPECT_TRUE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_PLATFORM_APP));
    657   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_APP_SHORTCUT));
    658   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP,
    659                                        TYPE_BROWSER_SHORTCUT));
    660   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_WINDOWED_APP));
    661   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_APP_LIST));
    662   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_APP_PANEL));
    663 
    664   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_SHORTCUT));
    665   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_SHORTCUT,
    666                                       TYPE_BROWSER_SHORTCUT));
    667   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT,
    668                                        TYPE_WINDOWED_APP));
    669   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_LIST));
    670   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_PANEL));
    671 
    672   EXPECT_TRUE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT,
    673                                       TYPE_BROWSER_SHORTCUT));
    674   EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT,
    675                                        TYPE_WINDOWED_APP));
    676   EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_APP_LIST));
    677   EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_APP_PANEL));
    678 
    679   EXPECT_TRUE(test_api_->SameDragType(TYPE_WINDOWED_APP, TYPE_WINDOWED_APP));
    680   EXPECT_FALSE(test_api_->SameDragType(TYPE_WINDOWED_APP, TYPE_APP_LIST));
    681   EXPECT_FALSE(test_api_->SameDragType(TYPE_WINDOWED_APP, TYPE_APP_PANEL));
    682 
    683   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_LIST, TYPE_APP_LIST));
    684   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_LIST, TYPE_APP_PANEL));
    685 
    686   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_PANEL, TYPE_APP_PANEL));
    687 }
    688 
    689 // Adds platform app button until overflow and verifies that the last added
    690 // platform app button is hidden.
    691 TEST_F(ShelfViewTest, AddBrowserUntilOverflow) {
    692   // All buttons should be visible.
    693   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    694             test_api_->GetButtonCount());
    695 
    696   // Add platform app button until overflow.
    697   int items_added = 0;
    698   LauncherID last_added = AddPlatformApp();
    699   while (!test_api_->IsOverflowButtonVisible()) {
    700     // Added button is visible after animation while in this loop.
    701     EXPECT_TRUE(GetButtonByID(last_added)->visible());
    702 
    703     last_added = AddPlatformApp();
    704     ++items_added;
    705     ASSERT_LT(items_added, 10000);
    706   }
    707 
    708   // The last added button should be invisible.
    709   EXPECT_FALSE(GetButtonByID(last_added)->visible());
    710 }
    711 
    712 // Adds one platform app button then adds app shortcut until overflow. Verifies
    713 // that the browser button gets hidden on overflow and last added app shortcut
    714 // is still visible.
    715 TEST_F(ShelfViewTest, AddAppShortcutWithBrowserButtonUntilOverflow) {
    716   // All buttons should be visible.
    717   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    718             test_api_->GetButtonCount());
    719 
    720   LauncherID browser_button_id = AddPlatformApp();
    721 
    722   // Add app shortcut until overflow.
    723   int items_added = 0;
    724   LauncherID last_added = AddAppShortcut();
    725   while (!test_api_->IsOverflowButtonVisible()) {
    726     // Added button is visible after animation while in this loop.
    727     EXPECT_TRUE(GetButtonByID(last_added)->visible());
    728 
    729     last_added = AddAppShortcut();
    730     ++items_added;
    731     ASSERT_LT(items_added, 10000);
    732   }
    733 
    734   // And the platform app button is invisible.
    735   EXPECT_FALSE(GetButtonByID(browser_button_id)->visible());
    736 }
    737 
    738 TEST_F(ShelfViewLegacyShelfLayoutTest,
    739        AddAppShortcutWithBrowserButtonUntilOverflow) {
    740   // All buttons should be visible.
    741   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    742             test_api_->GetButtonCount());
    743 
    744   LauncherID browser_button_id = AddPlatformApp();
    745 
    746   // Add app shortcut until overflow.
    747   int items_added = 0;
    748   LauncherID last_added = AddAppShortcut();
    749   while (!test_api_->IsOverflowButtonVisible()) {
    750     // Added button is visible after animation while in this loop.
    751     EXPECT_TRUE(GetButtonByID(last_added)->visible());
    752 
    753     last_added = AddAppShortcut();
    754     ++items_added;
    755     ASSERT_LT(items_added, 10000);
    756   }
    757 
    758   // The last added app short button should be visible.
    759   EXPECT_TRUE(GetButtonByID(last_added)->visible());
    760   // And the platform app button is invisible.
    761   EXPECT_FALSE(GetButtonByID(browser_button_id)->visible());
    762 }
    763 
    764 TEST_F(ShelfViewTest, AddPanelHidesPlatformAppButton) {
    765   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    766             test_api_->GetButtonCount());
    767 
    768   // Add platform app button until overflow, remember last visible platform app
    769   // button.
    770   int items_added = 0;
    771   LauncherID first_added = AddPlatformApp();
    772   EXPECT_TRUE(GetButtonByID(first_added)->visible());
    773   while (true) {
    774     LauncherID added = AddPlatformApp();
    775     if (test_api_->IsOverflowButtonVisible()) {
    776       EXPECT_FALSE(GetButtonByID(added)->visible());
    777       RemoveByID(added);
    778       break;
    779     }
    780     ++items_added;
    781     ASSERT_LT(items_added, 10000);
    782   }
    783 
    784   LauncherID panel = AddPanel();
    785   EXPECT_TRUE(test_api_->IsOverflowButtonVisible());
    786 
    787   RemoveByID(panel);
    788   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
    789 }
    790 
    791 TEST_F(ShelfViewLegacyShelfLayoutTest, AddPanelHidesPlatformAppButton) {
    792   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    793             test_api_->GetButtonCount());
    794 
    795   // Add platform app button until overflow, remember last visible platform app
    796   // button.
    797   int items_added = 0;
    798   LauncherID first_added = AddPlatformApp();
    799   EXPECT_TRUE(GetButtonByID(first_added)->visible());
    800   LauncherID last_visible = first_added;
    801   while (true) {
    802     LauncherID added = AddPlatformApp();
    803     if (test_api_->IsOverflowButtonVisible()) {
    804       EXPECT_FALSE(GetButtonByID(added)->visible());
    805       break;
    806     }
    807     last_visible = added;
    808     ++items_added;
    809     ASSERT_LT(items_added, 10000);
    810   }
    811 
    812   LauncherID panel = AddPanel();
    813   EXPECT_TRUE(GetButtonByID(panel)->visible());
    814   EXPECT_FALSE(GetButtonByID(last_visible)->visible());
    815 
    816   RemoveByID(panel);
    817   EXPECT_TRUE(GetButtonByID(last_visible)->visible());
    818 }
    819 
    820 // When there are more panels then platform app buttons we should hide panels
    821 // rather than platform apps.
    822 TEST_F(ShelfViewTest, PlatformAppHidesExcessPanels) {
    823   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    824             test_api_->GetButtonCount());
    825 
    826   // Add platform app button.
    827   LauncherID platform_app = AddPlatformApp();
    828   LauncherID first_panel = AddPanel();
    829 
    830   EXPECT_TRUE(GetButtonByID(platform_app)->visible());
    831   EXPECT_TRUE(GetButtonByID(first_panel)->visible());
    832 
    833   // Add panels until there is an overflow.
    834   LauncherID last_panel = first_panel;
    835   int items_added = 0;
    836   while (!test_api_->IsOverflowButtonVisible()) {
    837     last_panel = AddPanel();
    838     ++items_added;
    839     ASSERT_LT(items_added, 10000);
    840   }
    841 
    842   // The first panel should now be hidden by the new platform apps needing
    843   // space.
    844   EXPECT_FALSE(GetButtonByID(first_panel)->visible());
    845   EXPECT_TRUE(GetButtonByID(last_panel)->visible());
    846   EXPECT_TRUE(GetButtonByID(platform_app)->visible());
    847 
    848   // Adding platform apps should eventually begin to hide platform apps. We will
    849   // add platform apps until either the last panel or platform app is hidden.
    850   items_added = 0;
    851   while (GetButtonByID(platform_app)->visible() &&
    852          GetButtonByID(last_panel)->visible()) {
    853     platform_app = AddPlatformApp();
    854     ++items_added;
    855     ASSERT_LT(items_added, 10000);
    856   }
    857   EXPECT_TRUE(GetButtonByID(last_panel)->visible());
    858   EXPECT_FALSE(GetButtonByID(platform_app)->visible());
    859 }
    860 
    861 // Adds button until overflow then removes first added one. Verifies that
    862 // the last added one changes from invisible to visible and overflow
    863 // chevron is gone.
    864 TEST_F(ShelfViewTest, RemoveButtonRevealsOverflowed) {
    865   // All buttons should be visible.
    866   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    867             test_api_->GetButtonCount());
    868 
    869   // Add platform app buttons until overflow.
    870   int items_added = 0;
    871   LauncherID first_added = AddPlatformApp();
    872   LauncherID last_added = first_added;
    873   while (!test_api_->IsOverflowButtonVisible()) {
    874     last_added = AddPlatformApp();
    875     ++items_added;
    876     ASSERT_LT(items_added, 10000);
    877   }
    878 
    879   // Expect add more than 1 button. First added is visible and last is not.
    880   EXPECT_NE(first_added, last_added);
    881   EXPECT_TRUE(GetButtonByID(first_added)->visible());
    882   EXPECT_FALSE(GetButtonByID(last_added)->visible());
    883 
    884   // Remove first added.
    885   RemoveByID(first_added);
    886 
    887   // Last added button becomes visible and overflow chevron is gone.
    888   EXPECT_TRUE(GetButtonByID(last_added)->visible());
    889   EXPECT_EQ(1.0f, GetButtonByID(last_added)->layer()->opacity());
    890   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
    891 }
    892 
    893 // Verifies that remove last overflowed button should hide overflow chevron.
    894 TEST_F(ShelfViewTest, RemoveLastOverflowed) {
    895   // All buttons should be visible.
    896   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    897             test_api_->GetButtonCount());
    898 
    899   // Add platform app button until overflow.
    900   int items_added = 0;
    901   LauncherID last_added = AddPlatformApp();
    902   while (!test_api_->IsOverflowButtonVisible()) {
    903     last_added = AddPlatformApp();
    904     ++items_added;
    905     ASSERT_LT(items_added, 10000);
    906   }
    907 
    908   RemoveByID(last_added);
    909   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
    910 }
    911 
    912 // Adds platform app button without waiting for animation to finish and verifies
    913 // that all added buttons are visible.
    914 TEST_F(ShelfViewTest, AddButtonQuickly) {
    915   // All buttons should be visible.
    916   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
    917             test_api_->GetButtonCount());
    918 
    919   // Add a few platform buttons quickly without wait for animation.
    920   int added_count = 0;
    921   while (!test_api_->IsOverflowButtonVisible()) {
    922     AddPlatformAppNoWait();
    923     ++added_count;
    924     ASSERT_LT(added_count, 10000);
    925   }
    926 
    927   // ShelfView should be big enough to hold at least 3 new buttons.
    928   ASSERT_GE(added_count, 3);
    929 
    930   // Wait for the last animation to finish.
    931   test_api_->RunMessageLoopUntilAnimationsDone();
    932 
    933   // Verifies non-overflow buttons are visible.
    934   for (int i = 0; i <= test_api_->GetLastVisibleIndex(); ++i) {
    935     internal::ShelfButton* button = test_api_->GetButton(i);
    936     if (button) {
    937       EXPECT_TRUE(button->visible()) << "button index=" << i;
    938       EXPECT_EQ(1.0f, button->layer()->opacity()) << "button index=" << i;
    939     }
    940   }
    941 }
    942 
    943 // Check that model changes are handled correctly while a launcher icon is being
    944 // dragged.
    945 TEST_F(ShelfViewTest, ModelChangesWhileDragging) {
    946   internal::ShelfButtonHost* button_host = shelf_view_;
    947 
    948   std::vector<std::pair<LauncherID, views::View*> > id_map;
    949   SetupForDragTest(&id_map);
    950 
    951   // Dragging browser shortcut at index 1.
    952   EXPECT_TRUE(model_->items()[1].type == TYPE_BROWSER_SHORTCUT);
    953   views::View* dragged_button = SimulateDrag(
    954       internal::ShelfButtonHost::MOUSE, 1, 3);
    955   std::rotate(id_map.begin() + 1,
    956               id_map.begin() + 2,
    957               id_map.begin() + 4);
    958   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
    959   button_host->PointerReleasedOnButton(dragged_button,
    960                                        internal::ShelfButtonHost::MOUSE,
    961                                        false);
    962   EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT);
    963 
    964   // Dragging changes model order.
    965   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 1, 3);
    966   std::rotate(id_map.begin() + 1,
    967               id_map.begin() + 2,
    968               id_map.begin() + 4);
    969   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
    970 
    971   // Cancelling the drag operation restores previous order.
    972   button_host->PointerReleasedOnButton(dragged_button,
    973                                        internal::ShelfButtonHost::MOUSE,
    974                                        true);
    975   std::rotate(id_map.begin() + 1,
    976               id_map.begin() + 3,
    977               id_map.begin() + 4);
    978   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
    979 
    980   // Deleting an item keeps the remaining intact.
    981   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 1, 3);
    982   model_->RemoveItemAt(1);
    983   id_map.erase(id_map.begin() + 1);
    984   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
    985   button_host->PointerReleasedOnButton(dragged_button,
    986                                        internal::ShelfButtonHost::MOUSE,
    987                                        false);
    988 
    989   // Adding a launcher item cancels the drag and respects the order.
    990   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 1, 3);
    991   LauncherID new_id = AddAppShortcut();
    992   id_map.insert(id_map.begin() + 6,
    993                 std::make_pair(new_id, GetButtonByID(new_id)));
    994   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
    995   button_host->PointerReleasedOnButton(dragged_button,
    996                                        internal::ShelfButtonHost::MOUSE,
    997                                        false);
    998 
    999   // Adding a launcher item at the end (i.e. a panel)  canels drag and respects
   1000   // the order.
   1001   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 1, 3);
   1002   new_id = AddPanel();
   1003   id_map.insert(id_map.begin() + 7,
   1004                 std::make_pair(new_id, GetButtonByID(new_id)));
   1005   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1006   button_host->PointerReleasedOnButton(dragged_button,
   1007                                        internal::ShelfButtonHost::MOUSE,
   1008                                        false);
   1009 }
   1010 
   1011 TEST_F(ShelfViewLegacyShelfLayoutTest, ModelChangesWhileDragging) {
   1012   internal::ShelfButtonHost* button_host = shelf_view_;
   1013 
   1014   std::vector<std::pair<LauncherID, views::View*> > id_map;
   1015   SetupForDragTest(&id_map);
   1016 
   1017   // Dragging browser shortcut at index 0.
   1018   EXPECT_TRUE(model_->items()[0].type == TYPE_BROWSER_SHORTCUT);
   1019   views::View* dragged_button = SimulateDrag(
   1020       internal::ShelfButtonHost::MOUSE, 0, 2);
   1021   std::rotate(id_map.begin(),
   1022               id_map.begin() + 1,
   1023               id_map.begin() + 3);
   1024   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1025   button_host->PointerReleasedOnButton(dragged_button,
   1026                                        internal::ShelfButtonHost::MOUSE,
   1027                                        false);
   1028   EXPECT_TRUE(model_->items()[2].type == TYPE_BROWSER_SHORTCUT);
   1029 
   1030   // Dragging changes model order.
   1031   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 0, 2);
   1032   std::rotate(id_map.begin(),
   1033               id_map.begin() + 1,
   1034               id_map.begin() + 3);
   1035   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1036 
   1037   // Cancelling the drag operation restores previous order.
   1038   button_host->PointerReleasedOnButton(dragged_button,
   1039                                        internal::ShelfButtonHost::MOUSE,
   1040                                        true);
   1041   std::rotate(id_map.begin(),
   1042               id_map.begin() + 2,
   1043               id_map.begin() + 3);
   1044   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1045 
   1046   // Deleting an item keeps the remaining intact.
   1047   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 0, 2);
   1048   model_->RemoveItemAt(1);
   1049   id_map.erase(id_map.begin() + 1);
   1050   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1051   button_host->PointerReleasedOnButton(dragged_button,
   1052                                        internal::ShelfButtonHost::MOUSE,
   1053                                        false);
   1054 
   1055   // Adding a launcher item cancels the drag and respects the order.
   1056   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 0, 2);
   1057   LauncherID new_id = AddAppShortcut();
   1058   id_map.insert(id_map.begin() + 5,
   1059                 std::make_pair(new_id, GetButtonByID(new_id)));
   1060   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1061   button_host->PointerReleasedOnButton(dragged_button,
   1062                                        internal::ShelfButtonHost::MOUSE,
   1063                                        false);
   1064 
   1065   // Adding a launcher item at the end (i.e. a panel)  canels drag and respects
   1066   // the order.
   1067   dragged_button = SimulateDrag(internal::ShelfButtonHost::MOUSE, 0, 2);
   1068   new_id = AddPanel();
   1069   id_map.insert(id_map.begin() + 7,
   1070                 std::make_pair(new_id, GetButtonByID(new_id)));
   1071   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1072   button_host->PointerReleasedOnButton(dragged_button,
   1073                                        internal::ShelfButtonHost::MOUSE,
   1074                                        false);
   1075 }
   1076 
   1077 // Check that 2nd drag from the other pointer would be ignored.
   1078 TEST_F(ShelfViewTest, SimultaneousDrag) {
   1079   internal::ShelfButtonHost* button_host = shelf_view_;
   1080 
   1081   std::vector<std::pair<LauncherID, views::View*> > id_map;
   1082   SetupForDragTest(&id_map);
   1083 
   1084   // Start a mouse drag.
   1085   views::View* dragged_button_mouse = SimulateDrag(
   1086       internal::ShelfButtonHost::MOUSE, 1, 3);
   1087   std::rotate(id_map.begin() + 1,
   1088               id_map.begin() + 2,
   1089               id_map.begin() + 4);
   1090   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1091   // Attempt a touch drag before the mouse drag finishes.
   1092   views::View* dragged_button_touch = SimulateDrag(
   1093       internal::ShelfButtonHost::TOUCH, 4, 2);
   1094 
   1095   // Nothing changes since 2nd drag is ignored.
   1096   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1097 
   1098   // Finish the mouse drag.
   1099   button_host->PointerReleasedOnButton(dragged_button_mouse,
   1100                                        internal::ShelfButtonHost::MOUSE,
   1101                                        false);
   1102   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1103 
   1104   // Now start a touch drag.
   1105   dragged_button_touch = SimulateDrag(internal::ShelfButtonHost::TOUCH, 4, 2);
   1106   std::rotate(id_map.begin() + 3,
   1107               id_map.begin() + 4,
   1108               id_map.begin() + 5);
   1109   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1110 
   1111   // And attempt a mouse drag before the touch drag finishes.
   1112   dragged_button_mouse = SimulateDrag(internal::ShelfButtonHost::MOUSE, 1, 2);
   1113 
   1114   // Nothing changes since 2nd drag is ignored.
   1115   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1116 
   1117   button_host->PointerReleasedOnButton(dragged_button_touch,
   1118                                        internal::ShelfButtonHost::TOUCH,
   1119                                        false);
   1120   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1121 }
   1122 
   1123 // Check that clicking first on one item and then dragging another works as
   1124 // expected.
   1125 TEST_F(ShelfViewTest, ClickOneDragAnother) {
   1126   internal::ShelfButtonHost* button_host = shelf_view_;
   1127 
   1128   std::vector<std::pair<LauncherID, views::View*> > id_map;
   1129   SetupForDragTest(&id_map);
   1130 
   1131   // A click on item 1 is simulated.
   1132   SimulateClick(internal::ShelfButtonHost::MOUSE, 1);
   1133 
   1134   // Dragging browser index at 0 should change the model order correctly.
   1135   EXPECT_TRUE(model_->items()[1].type == TYPE_BROWSER_SHORTCUT);
   1136   views::View* dragged_button = SimulateDrag(
   1137       internal::ShelfButtonHost::MOUSE, 1, 3);
   1138   std::rotate(id_map.begin() + 1,
   1139               id_map.begin() + 2,
   1140               id_map.begin() + 4);
   1141   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
   1142   button_host->PointerReleasedOnButton(dragged_button,
   1143                                        internal::ShelfButtonHost::MOUSE,
   1144                                        false);
   1145   EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT);
   1146 }
   1147 
   1148 // Confirm that item status changes are reflected in the buttons.
   1149 TEST_F(ShelfViewTest, LauncherItemStatus) {
   1150   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
   1151             test_api_->GetButtonCount());
   1152 
   1153   // Add platform app button.
   1154   LauncherID last_added = AddPlatformApp();
   1155   LauncherItem item = GetItemByID(last_added);
   1156   int index = model_->ItemIndexByID(last_added);
   1157   internal::ShelfButton* button = GetButtonByID(last_added);
   1158   ASSERT_EQ(internal::ShelfButton::STATE_RUNNING, button->state());
   1159   item.status = STATUS_ACTIVE;
   1160   model_->Set(index, item);
   1161   ASSERT_EQ(internal::ShelfButton::STATE_ACTIVE, button->state());
   1162   item.status = STATUS_ATTENTION;
   1163   model_->Set(index, item);
   1164   ASSERT_EQ(internal::ShelfButton::STATE_ATTENTION, button->state());
   1165 }
   1166 
   1167 TEST_F(ShelfViewLegacyShelfLayoutTest,
   1168        LauncherItemPositionReflectedOnStateChanged) {
   1169   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
   1170             test_api_->GetButtonCount());
   1171 
   1172   // Add 2 items to the launcher.
   1173   LauncherID item1_id = AddPlatformApp();
   1174   LauncherID item2_id = AddPlatformAppNoWait();
   1175   internal::ShelfButton* item1_button = GetButtonByID(item1_id);
   1176   internal::ShelfButton* item2_button = GetButtonByID(item2_id);
   1177 
   1178   internal::ShelfButton::State state_mask =
   1179       static_cast<internal::ShelfButton::State>(
   1180           internal::ShelfButton::STATE_NORMAL |
   1181           internal::ShelfButton::STATE_HOVERED |
   1182           internal::ShelfButton::STATE_RUNNING |
   1183           internal::ShelfButton::STATE_ACTIVE |
   1184           internal::ShelfButton::STATE_ATTENTION |
   1185           internal::ShelfButton::STATE_FOCUSED);
   1186 
   1187   // Clear the button states.
   1188   item1_button->ClearState(state_mask);
   1189   item2_button->ClearState(state_mask);
   1190 
   1191   // Since default alignment in tests is bottom, state is reflected in y-axis.
   1192   ASSERT_EQ(item1_button->GetIconBounds().y(),
   1193             item2_button->GetIconBounds().y());
   1194   item1_button->AddState(internal::ShelfButton::STATE_HOVERED);
   1195   ASSERT_NE(item1_button->GetIconBounds().y(),
   1196             item2_button->GetIconBounds().y());
   1197   item1_button->ClearState(internal::ShelfButton::STATE_HOVERED);
   1198 }
   1199 
   1200 // Confirm that item status changes are reflected in the buttons
   1201 // for platform apps.
   1202 TEST_F(ShelfViewTest, LauncherItemStatusPlatformApp) {
   1203   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
   1204             test_api_->GetButtonCount());
   1205 
   1206   // Add platform app button.
   1207   LauncherID last_added = AddPlatformApp();
   1208   LauncherItem item = GetItemByID(last_added);
   1209   int index = model_->ItemIndexByID(last_added);
   1210   internal::ShelfButton* button = GetButtonByID(last_added);
   1211   ASSERT_EQ(internal::ShelfButton::STATE_RUNNING, button->state());
   1212   item.status = STATUS_ACTIVE;
   1213   model_->Set(index, item);
   1214   ASSERT_EQ(internal::ShelfButton::STATE_ACTIVE, button->state());
   1215   item.status = STATUS_ATTENTION;
   1216   model_->Set(index, item);
   1217   ASSERT_EQ(internal::ShelfButton::STATE_ATTENTION, button->state());
   1218 }
   1219 
   1220 // Confirm that launcher item bounds are correctly updated on shelf changes.
   1221 TEST_F(ShelfViewTest, LauncherItemBoundsCheck) {
   1222   VerifyLauncherItemBoundsAreValid();
   1223   shelf_view_->shelf_layout_manager()->SetAutoHideBehavior(
   1224       SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
   1225   test_api_->RunMessageLoopUntilAnimationsDone();
   1226   VerifyLauncherItemBoundsAreValid();
   1227   shelf_view_->shelf_layout_manager()->SetAutoHideBehavior(
   1228       SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
   1229   test_api_->RunMessageLoopUntilAnimationsDone();
   1230   VerifyLauncherItemBoundsAreValid();
   1231 }
   1232 
   1233 TEST_F(ShelfViewTest, ShelfTooltipTest) {
   1234   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
   1235             test_api_->GetButtonCount());
   1236 
   1237   // Prepare some items to the launcher.
   1238   LauncherID app_button_id = AddAppShortcut();
   1239   LauncherID platform_button_id = AddPlatformApp();
   1240 
   1241   internal::ShelfButton* app_button = GetButtonByID(app_button_id);
   1242   internal::ShelfButton* platform_button = GetButtonByID(platform_button_id);
   1243 
   1244   internal::ShelfButtonHost* button_host = shelf_view_;
   1245   internal::ShelfTooltipManager* tooltip_manager =
   1246       shelf_view_->tooltip_manager();
   1247 
   1248   button_host->MouseEnteredButton(app_button);
   1249   // There's a delay to show the tooltip, so it's not visible yet.
   1250   EXPECT_FALSE(tooltip_manager->IsVisible());
   1251   EXPECT_EQ(app_button, GetTooltipAnchorView());
   1252 
   1253   ShowTooltip();
   1254   EXPECT_TRUE(tooltip_manager->IsVisible());
   1255 
   1256   // Once it's visible, it keeps visibility and is pointing to the same
   1257   // item.
   1258   button_host->MouseExitedButton(app_button);
   1259   EXPECT_TRUE(tooltip_manager->IsVisible());
   1260   EXPECT_EQ(app_button, GetTooltipAnchorView());
   1261 
   1262   // When entered to another item, it switches to the new item.  There is no
   1263   // delay for the visibility.
   1264   button_host->MouseEnteredButton(platform_button);
   1265   EXPECT_TRUE(tooltip_manager->IsVisible());
   1266   EXPECT_EQ(platform_button, GetTooltipAnchorView());
   1267 
   1268   button_host->MouseExitedButton(platform_button);
   1269   tooltip_manager->Close();
   1270 
   1271   // Next time: enter app_button -> move immediately to tab_button.
   1272   button_host->MouseEnteredButton(app_button);
   1273   button_host->MouseExitedButton(app_button);
   1274   button_host->MouseEnteredButton(platform_button);
   1275   EXPECT_FALSE(tooltip_manager->IsVisible());
   1276   EXPECT_EQ(platform_button, GetTooltipAnchorView());
   1277 }
   1278 
   1279 // Verify a fix for crash caused by a tooltip update for a deleted launcher
   1280 // button, see crbug.com/288838.
   1281 TEST_F(ShelfViewTest, RemovingItemClosesTooltip) {
   1282   internal::ShelfButtonHost* button_host = shelf_view_;
   1283   internal::ShelfTooltipManager* tooltip_manager =
   1284       shelf_view_->tooltip_manager();
   1285 
   1286   // Add an item to the launcher.
   1287   LauncherID app_button_id = AddAppShortcut();
   1288   internal::ShelfButton* app_button = GetButtonByID(app_button_id);
   1289 
   1290   // Spawn a tooltip on that item.
   1291   button_host->MouseEnteredButton(app_button);
   1292   ShowTooltip();
   1293   EXPECT_TRUE(tooltip_manager->IsVisible());
   1294 
   1295   // Remove the app shortcut while the tooltip is open. The tooltip should be
   1296   // closed.
   1297   RemoveByID(app_button_id);
   1298   EXPECT_FALSE(tooltip_manager->IsVisible());
   1299 
   1300   // Change the shelf layout. This should not crash.
   1301   Shell::GetInstance()->SetShelfAlignment(SHELF_ALIGNMENT_LEFT,
   1302                                           Shell::GetPrimaryRootWindow());
   1303 }
   1304 
   1305 // Changing the shelf alignment closes any open tooltip.
   1306 TEST_F(ShelfViewTest, ShelfAlignmentClosesTooltip) {
   1307   internal::ShelfButtonHost* button_host = shelf_view_;
   1308   internal::ShelfTooltipManager* tooltip_manager =
   1309       shelf_view_->tooltip_manager();
   1310 
   1311   // Add an item to the launcher.
   1312   LauncherID app_button_id = AddAppShortcut();
   1313   internal::ShelfButton* app_button = GetButtonByID(app_button_id);
   1314 
   1315   // Spawn a tooltip on the item.
   1316   button_host->MouseEnteredButton(app_button);
   1317   ShowTooltip();
   1318   EXPECT_TRUE(tooltip_manager->IsVisible());
   1319 
   1320   // Changing shelf alignment hides the tooltip.
   1321   Shell::GetInstance()->SetShelfAlignment(SHELF_ALIGNMENT_LEFT,
   1322                                           Shell::GetPrimaryRootWindow());
   1323   EXPECT_FALSE(tooltip_manager->IsVisible());
   1324 }
   1325 
   1326 TEST_F(ShelfViewTest, ShouldHideTooltipTest) {
   1327   LauncherID app_button_id = AddAppShortcut();
   1328   LauncherID platform_button_id = AddPlatformApp();
   1329 
   1330   // The tooltip shouldn't hide if the mouse is on normal buttons.
   1331   for (int i = 0; i < test_api_->GetButtonCount(); i++) {
   1332     internal::ShelfButton* button = test_api_->GetButton(i);
   1333     if (!button)
   1334       continue;
   1335 
   1336     EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
   1337         button->GetMirroredBounds().CenterPoint()))
   1338         << "ShelfView tries to hide on button " << i;
   1339   }
   1340 
   1341   // The tooltip should not hide on the app-list button.
   1342   views::View* app_list_button = shelf_view_->GetAppListButtonView();
   1343   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
   1344       app_list_button->GetMirroredBounds().CenterPoint()));
   1345 
   1346   // The tooltip shouldn't hide if the mouse is in the gap between two buttons.
   1347   gfx::Rect app_button_rect = GetButtonByID(app_button_id)->GetMirroredBounds();
   1348   gfx::Rect platform_button_rect =
   1349       GetButtonByID(platform_button_id)->GetMirroredBounds();
   1350   ASSERT_FALSE(app_button_rect.Intersects(platform_button_rect));
   1351   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
   1352       gfx::UnionRects(app_button_rect, platform_button_rect).CenterPoint()));
   1353 
   1354   // The tooltip should hide if it's outside of all buttons.
   1355   gfx::Rect all_area;
   1356   for (int i = 0; i < test_api_->GetButtonCount(); i++) {
   1357     internal::ShelfButton* button = test_api_->GetButton(i);
   1358     if (!button)
   1359       continue;
   1360 
   1361     all_area.Union(button->GetMirroredBounds());
   1362   }
   1363   all_area.Union(shelf_view_->GetAppListButtonView()->GetMirroredBounds());
   1364   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(all_area.origin()));
   1365   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
   1366       gfx::Point(all_area.right() - 1, all_area.bottom() - 1)));
   1367   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
   1368       gfx::Point(all_area.right(), all_area.y())));
   1369   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
   1370       gfx::Point(all_area.x() - 1, all_area.y())));
   1371   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
   1372       gfx::Point(all_area.x(), all_area.y() - 1)));
   1373   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
   1374       gfx::Point(all_area.x(), all_area.bottom())));
   1375 }
   1376 
   1377 TEST_F(ShelfViewTest, ShouldHideTooltipWithAppListWindowTest) {
   1378   Shell::GetInstance()->ToggleAppList(NULL);
   1379   ASSERT_TRUE(Shell::GetInstance()->GetAppListWindow());
   1380 
   1381   // The tooltip shouldn't hide if the mouse is on normal buttons.
   1382   for (int i = 1; i < test_api_->GetButtonCount(); i++) {
   1383     internal::ShelfButton* button = test_api_->GetButton(i);
   1384     if (!button)
   1385       continue;
   1386 
   1387     EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
   1388         button->GetMirroredBounds().CenterPoint()))
   1389         << "ShelfView tries to hide on button " << i;
   1390   }
   1391 
   1392   // The tooltip should hide on the app-list button.
   1393   views::View* app_list_button = shelf_view_->GetAppListButtonView();
   1394   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
   1395       app_list_button->GetMirroredBounds().CenterPoint()));
   1396 }
   1397 
   1398 // Test that by moving the mouse cursor off the button onto the bubble it closes
   1399 // the bubble.
   1400 TEST_F(ShelfViewTest, ShouldHideTooltipWhenHoveringOnTooltip) {
   1401   internal::ShelfTooltipManager* tooltip_manager =
   1402       shelf_view_->tooltip_manager();
   1403   tooltip_manager->CreateZeroDelayTimerForTest();
   1404   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
   1405 
   1406   // Move the mouse off any item and check that no tooltip is shown.
   1407   generator.MoveMouseTo(gfx::Point(0, 0));
   1408   EXPECT_FALSE(tooltip_manager->IsVisible());
   1409 
   1410   // Move the mouse over the button and check that it is visible.
   1411   views::View* app_list_button = shelf_view_->GetAppListButtonView();
   1412   gfx::Rect bounds = app_list_button->GetBoundsInScreen();
   1413   generator.MoveMouseTo(bounds.CenterPoint());
   1414   // Wait for the timer to go off.
   1415   RunAllPendingInMessageLoop();
   1416   EXPECT_TRUE(tooltip_manager->IsVisible());
   1417 
   1418   // Move the mouse cursor slightly to the right of the item. The tooltip should
   1419   // stay open.
   1420   generator.MoveMouseBy(bounds.width() / 2 + 5, 0);
   1421   // Make sure there is no delayed close.
   1422   RunAllPendingInMessageLoop();
   1423   EXPECT_TRUE(tooltip_manager->IsVisible());
   1424 
   1425   // Move back - it should still stay open.
   1426   generator.MoveMouseBy(-(bounds.width() / 2 + 5), 0);
   1427   // Make sure there is no delayed close.
   1428   RunAllPendingInMessageLoop();
   1429   EXPECT_TRUE(tooltip_manager->IsVisible());
   1430 
   1431   // Now move the mouse cursor slightly above the item - so that it is over the
   1432   // tooltip bubble. Now it should disappear.
   1433   generator.MoveMouseBy(0, -(bounds.height() / 2 + 5));
   1434   // Wait until the delayed close kicked in.
   1435   RunAllPendingInMessageLoop();
   1436   EXPECT_FALSE(tooltip_manager->IsVisible());
   1437 }
   1438 
   1439 // Resizing shelf view while an add animation without fade-in is running,
   1440 // which happens when overflow happens. App list button should end up in its
   1441 // new ideal bounds.
   1442 TEST_F(ShelfViewTest, ResizeDuringOverflowAddAnimation) {
   1443   // All buttons should be visible.
   1444   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
   1445             test_api_->GetButtonCount());
   1446 
   1447   // Add buttons until overflow. Let the non-overflow add animations finish but
   1448   // leave the last running.
   1449   int items_added = 0;
   1450   AddPlatformAppNoWait();
   1451   while (!test_api_->IsOverflowButtonVisible()) {
   1452     test_api_->RunMessageLoopUntilAnimationsDone();
   1453     AddPlatformAppNoWait();
   1454     ++items_added;
   1455     ASSERT_LT(items_added, 10000);
   1456   }
   1457 
   1458   // Resize shelf view with that animation running and stay overflown.
   1459   gfx::Rect bounds = shelf_view_->bounds();
   1460   bounds.set_width(bounds.width() - kLauncherPreferredSize);
   1461   shelf_view_->SetBoundsRect(bounds);
   1462   ASSERT_TRUE(test_api_->IsOverflowButtonVisible());
   1463 
   1464   // Finish the animation.
   1465   test_api_->RunMessageLoopUntilAnimationsDone();
   1466 
   1467   // App list button should ends up in its new ideal bounds.
   1468   const int app_list_button_index = test_api_->GetButtonCount() - 1;
   1469   const gfx::Rect& app_list_ideal_bounds =
   1470       test_api_->GetIdealBoundsByIndex(app_list_button_index);
   1471   const gfx::Rect& app_list_bounds =
   1472       test_api_->GetBoundsByIndex(app_list_button_index);
   1473   EXPECT_EQ(app_list_bounds, app_list_ideal_bounds);
   1474 }
   1475 
   1476 // Checks the overflow bubble size when an item is ripped off and re-inserted.
   1477 TEST_F(ShelfViewTest, OverflowBubbleSize) {
   1478   // Replace ShelfDelegate.
   1479   test::ShellTestApi test_api(Shell::GetInstance());
   1480   test_api.SetShelfDelegate(NULL);
   1481   ShelfDelegate *delegate = new TestShelfDelegateForShelfView(model_);
   1482   test_api.SetShelfDelegate(delegate);
   1483   test::LauncherTestAPI(
   1484       Launcher::ForPrimaryDisplay()).SetShelfDelegate(delegate);
   1485   test_api_->SetShelfDelegate(delegate);
   1486 
   1487   AddButtonsUntilOverflow();
   1488 
   1489   // Show overflow bubble.
   1490   test_api_->ShowOverflowBubble();
   1491   ASSERT_TRUE(test_api_->overflow_bubble() &&
   1492               test_api_->overflow_bubble()->IsShowing());
   1493 
   1494   ShelfViewTestAPI test_for_overflow_view(
   1495       test_api_->overflow_bubble()->shelf_view());
   1496 
   1497   int ripped_index = test_for_overflow_view.GetLastVisibleIndex();
   1498   gfx::Size bubble_size = test_for_overflow_view.GetPreferredSize();
   1499   int item_width = test_for_overflow_view.GetButtonSize() +
   1500       test_for_overflow_view.GetButtonSpacing();
   1501 
   1502   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
   1503                                        gfx::Point());
   1504   internal::ShelfButton* button =
   1505       test_for_overflow_view.GetButton(ripped_index);
   1506   // Rip off the last visible item.
   1507   gfx::Point start_point = button->GetBoundsInScreen().CenterPoint();
   1508   gfx::Point rip_off_point(start_point.x(), 0);
   1509   generator.MoveMouseTo(start_point.x(), start_point.y());
   1510   base::MessageLoop::current()->RunUntilIdle();
   1511   generator.PressLeftButton();
   1512   base::MessageLoop::current()->RunUntilIdle();
   1513   generator.MoveMouseTo(rip_off_point.x(), rip_off_point.y());
   1514   base::MessageLoop::current()->RunUntilIdle();
   1515   test_for_overflow_view.RunMessageLoopUntilAnimationsDone();
   1516 
   1517   // Check the overflow bubble size when an item is ripped off.
   1518   EXPECT_EQ(bubble_size.width() - item_width,
   1519             test_for_overflow_view.GetPreferredSize().width());
   1520   ASSERT_TRUE(test_api_->overflow_bubble() &&
   1521               test_api_->overflow_bubble()->IsShowing());
   1522 
   1523   // Re-insert an item into the overflow bubble.
   1524   int first_index = test_for_overflow_view.GetFirstVisibleIndex();
   1525   button = test_for_overflow_view.GetButton(first_index);
   1526 
   1527   // Check the bubble size after an item is re-inserted.
   1528   generator.MoveMouseTo(button->GetBoundsInScreen().CenterPoint());
   1529   test_for_overflow_view.RunMessageLoopUntilAnimationsDone();
   1530   EXPECT_EQ(bubble_size.width(),
   1531             test_for_overflow_view.GetPreferredSize().width());
   1532 
   1533   generator.ReleaseLeftButton();
   1534   test_for_overflow_view.RunMessageLoopUntilAnimationsDone();
   1535   EXPECT_EQ(bubble_size.width(),
   1536             test_for_overflow_view.GetPreferredSize().width());
   1537 }
   1538 
   1539 // Check that the first item in the list follows Fitt's law by including the
   1540 // first pixel and being therefore bigger then the others.
   1541 TEST_F(ShelfViewLegacyShelfLayoutTest, CheckFittsLaw) {
   1542   // All buttons should be visible.
   1543   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
   1544             test_api_->GetButtonCount());
   1545   gfx::Rect ideal_bounds_0 = test_api_->GetIdealBoundsByIndex(0);
   1546   gfx::Rect ideal_bounds_1 = test_api_->GetIdealBoundsByIndex(1);
   1547   EXPECT_GT(ideal_bounds_0.width(), ideal_bounds_1.width());
   1548 }
   1549 
   1550 // Check the drag insertion bounds of scrolled overflow bubble.
   1551 TEST_F(ShelfViewTest, CheckDragInsertBoundsOfScrolledOverflowBubble) {
   1552   UpdateDisplay("400x300");
   1553 
   1554   EXPECT_EQ(2, model_->item_count());
   1555 
   1556   AddButtonsUntilOverflow();
   1557 
   1558   // Show overflow bubble.
   1559   test_api_->ShowOverflowBubble();
   1560   ASSERT_TRUE(test_api_->overflow_bubble() &&
   1561               test_api_->overflow_bubble()->IsShowing());
   1562 
   1563   int item_width = test_api_->GetButtonSize() +
   1564       test_api_->GetButtonSpacing();
   1565   internal::OverflowBubbleView* bubble_view =
   1566       test_api_->overflow_bubble()->bubble_view();
   1567   test::OverflowBubbleViewTestAPI bubble_view_api(bubble_view);
   1568 
   1569   // Add more buttons until OverflowBubble is scrollable and it has 3 invisible
   1570   // items.
   1571   while (bubble_view_api.GetContentsSize().width() <
   1572          (bubble_view->GetContentsBounds().width() + 3 * item_width))
   1573     AddAppShortcut();
   1574 
   1575   ASSERT_TRUE(test_api_->overflow_bubble() &&
   1576               test_api_->overflow_bubble()->IsShowing());
   1577 
   1578   ShelfViewTestAPI test_for_overflow_view(
   1579       test_api_->overflow_bubble()->shelf_view());
   1580   int first_index = test_for_overflow_view.GetFirstVisibleIndex();
   1581   int last_index = test_for_overflow_view.GetLastVisibleIndex();
   1582 
   1583   internal::ShelfButton* first_button =
   1584       test_for_overflow_view.GetButton(first_index);
   1585   internal::ShelfButton* last_button =
   1586       test_for_overflow_view.GetButton(last_index);
   1587   gfx::Point first_point = first_button->GetBoundsInScreen().CenterPoint();
   1588   gfx::Point last_point = last_button->GetBoundsInScreen().CenterPoint();
   1589   gfx::Rect drag_reinsert_bounds =
   1590       test_for_overflow_view.GetBoundsForDragInsertInScreen();
   1591   EXPECT_TRUE(drag_reinsert_bounds.Contains(first_point));
   1592   EXPECT_FALSE(drag_reinsert_bounds.Contains(last_point));
   1593 
   1594   // Scrolls sufficiently to show last item.
   1595   bubble_view_api.ScrollByXOffset(3 * item_width);
   1596   drag_reinsert_bounds =
   1597       test_for_overflow_view.GetBoundsForDragInsertInScreen();
   1598   first_point = first_button->GetBoundsInScreen().CenterPoint();
   1599   last_point = last_button->GetBoundsInScreen().CenterPoint();
   1600   EXPECT_FALSE(drag_reinsert_bounds.Contains(first_point));
   1601   EXPECT_TRUE(drag_reinsert_bounds.Contains(last_point));
   1602 }
   1603 
   1604 // Check the drag insertion bounds of shelf view in multi monitor environment.
   1605 TEST_F(ShelfViewTest, CheckDragInsertBoundsWithMultiMonitor) {
   1606   // win8-aura doesn't support multiple display.
   1607   if (!SupportsMultipleDisplays())
   1608     return;
   1609 
   1610   UpdateDisplay("800x600,800x600");
   1611   Launcher* secondary_launcher =
   1612       Launcher::ForWindow(Shell::GetAllRootWindows()[1]);
   1613   internal::ShelfView* shelf_view_for_secondary =
   1614       test::LauncherTestAPI(secondary_launcher).shelf_view();
   1615 
   1616   // The bounds should be big enough for 4 buttons + overflow chevron.
   1617   shelf_view_for_secondary->SetBounds(0, 0, 500,
   1618       internal::ShelfLayoutManager::GetPreferredShelfSize());
   1619 
   1620   ShelfViewTestAPI test_api_for_secondary(shelf_view_for_secondary);
   1621   // Speeds up animation for test.
   1622   test_api_for_secondary.SetAnimationDuration(1);
   1623 
   1624   AddButtonsUntilOverflow();
   1625 
   1626   // Test #1: Test drag insertion bounds of primary shelf.
   1627   // Show overflow bubble.
   1628   test_api_->ShowOverflowBubble();
   1629   ASSERT_TRUE(test_api_->overflow_bubble() &&
   1630               test_api_->overflow_bubble()->IsShowing());
   1631 
   1632   ShelfViewTestAPI test_api_for_overflow_view(
   1633       test_api_->overflow_bubble()->shelf_view());
   1634 
   1635   internal::ShelfButton* button = test_api_for_overflow_view.GetButton(
   1636       test_api_for_overflow_view.GetLastVisibleIndex());
   1637 
   1638   // Checks that a point in shelf is contained in drag insert bounds.
   1639   gfx::Point point_in_shelf_view = button->GetBoundsInScreen().CenterPoint();
   1640   gfx::Rect drag_reinsert_bounds =
   1641       test_api_for_overflow_view.GetBoundsForDragInsertInScreen();
   1642   EXPECT_TRUE(drag_reinsert_bounds.Contains(point_in_shelf_view));
   1643   // Checks that a point out of shelf is not contained in drag insert bounds.
   1644   EXPECT_FALSE(drag_reinsert_bounds.Contains(
   1645       gfx::Point(point_in_shelf_view.x(), 0)));
   1646 
   1647   // Test #2: Test drag insertion bounds of secondary shelf.
   1648   // Show overflow bubble.
   1649   test_api_for_secondary.ShowOverflowBubble();
   1650   ASSERT_TRUE(test_api_for_secondary.overflow_bubble() &&
   1651               test_api_for_secondary.overflow_bubble()->IsShowing());
   1652 
   1653   ShelfViewTestAPI test_api_for_overflow_view_of_secondary(
   1654       test_api_for_secondary.overflow_bubble()->shelf_view());
   1655 
   1656   internal::ShelfButton* button_in_secondary =
   1657       test_api_for_overflow_view_of_secondary.GetButton(
   1658           test_api_for_overflow_view_of_secondary.GetLastVisibleIndex());
   1659 
   1660   // Checks that a point in shelf is contained in drag insert bounds.
   1661   gfx::Point point_in_secondary_shelf_view =
   1662       button_in_secondary->GetBoundsInScreen().CenterPoint();
   1663   gfx::Rect drag_reinsert_bounds_in_secondary =
   1664       test_api_for_overflow_view_of_secondary.GetBoundsForDragInsertInScreen();
   1665   EXPECT_TRUE(drag_reinsert_bounds_in_secondary.Contains(
   1666       point_in_secondary_shelf_view));
   1667   // Checks that a point out of shelf is not contained in drag insert bounds.
   1668   EXPECT_FALSE(drag_reinsert_bounds_in_secondary.Contains(
   1669       gfx::Point(point_in_secondary_shelf_view.x(), 0)));
   1670   // Checks that a point of overflow bubble in primary shelf should not be
   1671   // contained by insert bounds of secondary shelf.
   1672   EXPECT_FALSE(drag_reinsert_bounds_in_secondary.Contains(point_in_shelf_view));
   1673 }
   1674 
   1675 // Checks the rip an item off from left aligned shelf in secondary monitor.
   1676 TEST_F(ShelfViewTest, CheckRipOffFromLeftShelfAlignmentWithMultiMonitor) {
   1677   // win8-aura doesn't support multiple display.
   1678   if (!SupportsMultipleDisplays())
   1679     return;
   1680 
   1681   UpdateDisplay("800x600,800x600");
   1682   ASSERT_EQ(2U, Shell::GetAllRootWindows().size());
   1683 
   1684   aura::Window* second_root = Shell::GetAllRootWindows()[1];
   1685 
   1686   Shell::GetInstance()->SetShelfAlignment(SHELF_ALIGNMENT_LEFT, second_root);
   1687   ASSERT_EQ(SHELF_ALIGNMENT_LEFT,
   1688             Shell::GetInstance()->GetShelfAlignment(second_root));
   1689 
   1690   // Initially, app list and browser shortcut are added.
   1691   EXPECT_EQ(2, model_->item_count());
   1692   int browser_index = model_->GetItemIndexForType(TYPE_BROWSER_SHORTCUT);
   1693   EXPECT_GT(browser_index, 0);
   1694 
   1695   Launcher* secondary_launcher = Launcher::ForWindow(second_root);
   1696   internal::ShelfView* shelf_view_for_secondary =
   1697       test::LauncherTestAPI(secondary_launcher).shelf_view();
   1698 
   1699   ShelfViewTestAPI test_api_for_secondary_shelf_view(shelf_view_for_secondary);
   1700   internal::ShelfButton* button =
   1701     test_api_for_secondary_shelf_view.GetButton(browser_index);
   1702 
   1703   // Fetch the start point of dragging.
   1704   gfx::Point start_point = button->GetBoundsInScreen().CenterPoint();
   1705   wm::ConvertPointFromScreen(second_root, &start_point);
   1706 
   1707   aura::test::EventGenerator generator(second_root, start_point);
   1708 
   1709   // Rip off the browser item.
   1710   generator.PressLeftButton();
   1711   generator.MoveMouseTo(start_point.x() + 400, start_point.y());
   1712   test_api_for_secondary_shelf_view.RunMessageLoopUntilAnimationsDone();
   1713   EXPECT_TRUE(test_api_for_secondary_shelf_view.IsRippedOffFromShelf());
   1714 }
   1715 
   1716 // Checks various drag and drop operations from OverflowBubble to Shelf.
   1717 TEST_F(ShelfViewTest, CheckDragAndDropFromOverflowBubbleToShelf) {
   1718   // Replace LauncherDelegate.
   1719   test::ShellTestApi test_api(Shell::GetInstance());
   1720   test_api.SetShelfDelegate(NULL);
   1721   ShelfDelegate *delegate = new TestShelfDelegateForShelfView(model_);
   1722   test_api.SetShelfDelegate(delegate);
   1723   test::LauncherTestAPI(
   1724       Launcher::ForPrimaryDisplay()).SetShelfDelegate(delegate);
   1725   test_api_->SetShelfDelegate(delegate);
   1726 
   1727   AddButtonsUntilOverflow();
   1728 
   1729   TestDraggingAnItemFromOverflowToShelf(false);
   1730   TestDraggingAnItemFromOverflowToShelf(true);
   1731 }
   1732 
   1733 class ShelfViewVisibleBoundsTest : public ShelfViewTest,
   1734                                    public testing::WithParamInterface<bool> {
   1735  public:
   1736   ShelfViewVisibleBoundsTest() : text_direction_change_(GetParam()) {}
   1737 
   1738   void CheckAllItemsAreInBounds() {
   1739     gfx::Rect visible_bounds = shelf_view_->GetVisibleItemsBoundsInScreen();
   1740     gfx::Rect launcher_bounds = shelf_view_->GetBoundsInScreen();
   1741     EXPECT_TRUE(launcher_bounds.Contains(visible_bounds));
   1742     for (int i = 0; i < test_api_->GetButtonCount(); ++i)
   1743       if (internal::ShelfButton* button = test_api_->GetButton(i))
   1744         EXPECT_TRUE(visible_bounds.Contains(button->GetBoundsInScreen()));
   1745     CheckAppListButtonIsInBounds();
   1746   }
   1747 
   1748   void CheckAppListButtonIsInBounds() {
   1749     gfx::Rect visible_bounds = shelf_view_->GetVisibleItemsBoundsInScreen();
   1750     gfx::Rect app_list_button_bounds = shelf_view_->GetAppListButtonView()->
   1751        GetBoundsInScreen();
   1752     EXPECT_TRUE(visible_bounds.Contains(app_list_button_bounds));
   1753   }
   1754 
   1755  private:
   1756   ScopedTextDirectionChange text_direction_change_;
   1757 
   1758   DISALLOW_COPY_AND_ASSIGN(ShelfViewVisibleBoundsTest);
   1759 };
   1760 
   1761 TEST_P(ShelfViewVisibleBoundsTest, ItemsAreInBounds) {
   1762   // Adding elements leaving some empty space.
   1763   for (int i = 0; i < 3; i++) {
   1764     AddAppShortcut();
   1765   }
   1766   test_api_->RunMessageLoopUntilAnimationsDone();
   1767   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
   1768   CheckAllItemsAreInBounds();
   1769   // Same for overflow case.
   1770   while (!test_api_->IsOverflowButtonVisible()) {
   1771     AddAppShortcut();
   1772   }
   1773   test_api_->RunMessageLoopUntilAnimationsDone();
   1774   CheckAllItemsAreInBounds();
   1775 }
   1776 
   1777 INSTANTIATE_TEST_CASE_P(LtrRtl, ShelfViewTextDirectionTest, testing::Bool());
   1778 INSTANTIATE_TEST_CASE_P(VisibleBounds, ShelfViewVisibleBoundsTest,
   1779     testing::Bool());
   1780 
   1781 }  // namespace test
   1782 }  // namespace ash
   1783