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