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