- add sources.
[platform/framework/web/crosswalk.git] / src / ash / shelf / shelf_view_unittest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/shelf/shelf_view.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "ash/ash_switches.h"
11 #include "ash/launcher/launcher.h"
12 #include "ash/launcher/launcher_button.h"
13 #include "ash/launcher/launcher_item_delegate_manager.h"
14 #include "ash/launcher/launcher_model.h"
15 #include "ash/launcher/launcher_types.h"
16 #include "ash/root_window_controller.h"
17 #include "ash/shelf/shelf_icon_observer.h"
18 #include "ash/shelf/shelf_layout_manager.h"
19 #include "ash/shelf/shelf_tooltip_manager.h"
20 #include "ash/shelf/shelf_widget.h"
21 #include "ash/shell.h"
22 #include "ash/shell_window_ids.h"
23 #include "ash/test/ash_test_base.h"
24 #include "ash/test/launcher_test_api.h"
25 #include "ash/test/shelf_view_test_api.h"
26 #include "ash/test/shell_test_api.h"
27 #include "ash/test/test_launcher_delegate.h"
28 #include "ash/test/test_launcher_item_delegate.h"
29 #include "base/basictypes.h"
30 #include "base/command_line.h"
31 #include "base/compiler_specific.h"
32 #include "base/memory/scoped_ptr.h"
33 #include "grit/ash_resources.h"
34 #include "ui/aura/root_window.h"
35 #include "ui/aura/test/aura_test_base.h"
36 #include "ui/aura/test/event_generator.h"
37 #include "ui/aura/window.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/compositor/layer.h"
40 #include "ui/events/event.h"
41 #include "ui/events/event_constants.h"
42 #include "ui/views/view_model.h"
43 #include "ui/views/widget/widget.h"
44 #include "ui/views/widget/widget_delegate.h"
45
46 namespace ash {
47 namespace test {
48
49 ////////////////////////////////////////////////////////////////////////////////
50 // ShelfIconObserver tests.
51
52 class TestShelfIconObserver : public ShelfIconObserver {
53  public:
54   explicit TestShelfIconObserver(Launcher* launcher)
55       : launcher_(launcher),
56         change_notified_(false) {
57     if (launcher_)
58       launcher_->AddIconObserver(this);
59   }
60
61   virtual ~TestShelfIconObserver() {
62     if (launcher_)
63       launcher_->RemoveIconObserver(this);
64   }
65
66   // ShelfIconObserver implementation.
67   virtual void OnShelfIconPositionsChanged() OVERRIDE {
68     change_notified_ = true;
69   }
70
71   int change_notified() const { return change_notified_; }
72   void Reset() { change_notified_ = false; }
73
74  private:
75   Launcher* launcher_;
76   bool change_notified_;
77
78   DISALLOW_COPY_AND_ASSIGN(TestShelfIconObserver);
79 };
80
81 class ShelfViewIconObserverTest : public ash::test::AshTestBase {
82  public:
83   ShelfViewIconObserverTest() {}
84   virtual ~ShelfViewIconObserverTest() {}
85
86   virtual void SetUp() OVERRIDE {
87     AshTestBase::SetUp();
88     Launcher* launcher = Launcher::ForPrimaryDisplay();
89     observer_.reset(new TestShelfIconObserver(launcher));
90
91     shelf_view_test_.reset(new ShelfViewTestAPI(
92         LauncherTestAPI(launcher).shelf_view()));
93     shelf_view_test_->SetAnimationDuration(1);
94   }
95
96   virtual void TearDown() OVERRIDE {
97     observer_.reset();
98     AshTestBase::TearDown();
99   }
100
101   TestShelfIconObserver* observer() { return observer_.get(); }
102
103   ShelfViewTestAPI* shelf_view_test() {
104     return shelf_view_test_.get();
105   }
106
107   Launcher* LauncherForSecondaryDisplay() {
108     return Launcher::ForWindow(Shell::GetAllRootWindows()[1]);
109   }
110
111  private:
112   scoped_ptr<TestShelfIconObserver> observer_;
113   scoped_ptr<ShelfViewTestAPI> shelf_view_test_;
114
115   DISALLOW_COPY_AND_ASSIGN(ShelfViewIconObserverTest);
116 };
117
118 TEST_F(ShelfViewIconObserverTest, AddRemove) {
119   ash::test::TestLauncherDelegate* launcher_delegate =
120       ash::test::TestLauncherDelegate::instance();
121   ASSERT_TRUE(launcher_delegate);
122
123   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
124   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
125   params.bounds = gfx::Rect(0, 0, 200, 200);
126   params.context = CurrentContext();
127
128   scoped_ptr<views::Widget> widget(new views::Widget());
129   widget->Init(params);
130   launcher_delegate->AddLauncherItem(widget->GetNativeWindow());
131   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
132   EXPECT_TRUE(observer()->change_notified());
133   observer()->Reset();
134
135   widget->Show();
136   widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
137   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
138   EXPECT_TRUE(observer()->change_notified());
139   observer()->Reset();
140 }
141
142 // Sometimes fails on trybots on win7_aura. http://crbug.com/177135
143 #if defined(OS_WIN)
144 #define MAYBE_AddRemoveWithMultipleDisplays \
145     DISABLED_AddRemoveWithMultipleDisplays
146 #else
147 #define MAYBE_AddRemoveWithMultipleDisplays \
148     AddRemoveWithMultipleDisplays
149 #endif
150 // Make sure creating/deleting an window on one displays notifies a
151 // launcher on external display as well as one on primary.
152 TEST_F(ShelfViewIconObserverTest, MAYBE_AddRemoveWithMultipleDisplays) {
153   UpdateDisplay("400x400,400x400");
154   TestShelfIconObserver second_observer(LauncherForSecondaryDisplay());
155
156   ash::test::TestLauncherDelegate* launcher_delegate =
157       ash::test::TestLauncherDelegate::instance();
158   ASSERT_TRUE(launcher_delegate);
159
160   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
161   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
162   params.bounds = gfx::Rect(0, 0, 200, 200);
163   params.context = CurrentContext();
164
165   scoped_ptr<views::Widget> widget(new views::Widget());
166   widget->Init(params);
167   launcher_delegate->AddLauncherItem(widget->GetNativeWindow());
168   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
169   EXPECT_TRUE(observer()->change_notified());
170   EXPECT_TRUE(second_observer.change_notified());
171   observer()->Reset();
172   second_observer.Reset();
173
174   widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
175   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
176   EXPECT_TRUE(observer()->change_notified());
177   EXPECT_TRUE(second_observer.change_notified());
178
179   observer()->Reset();
180   second_observer.Reset();
181 }
182
183 TEST_F(ShelfViewIconObserverTest, BoundsChanged) {
184   ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
185   Launcher* launcher = Launcher::ForPrimaryDisplay();
186   gfx::Size shelf_size =
187       shelf->GetWindowBoundsInScreen().size();
188   shelf_size.set_width(shelf_size.width() / 2);
189   ASSERT_GT(shelf_size.width(), 0);
190   launcher->SetShelfViewBounds(gfx::Rect(shelf_size));
191   // No animation happens for ShelfView bounds change.
192   EXPECT_TRUE(observer()->change_notified());
193   observer()->Reset();
194 }
195
196 ////////////////////////////////////////////////////////////////////////////////
197 // ShelfView tests.
198
199 class ShelfViewTest : public AshTestBase {
200  public:
201   ShelfViewTest() : model_(NULL), shelf_view_(NULL), browser_index_(1) {}
202   virtual ~ShelfViewTest() {}
203
204   virtual void SetUp() OVERRIDE {
205     AshTestBase::SetUp();
206     test::ShellTestApi test_api(Shell::GetInstance());
207     model_ = test_api.launcher_model();
208     Launcher* launcher = Launcher::ForPrimaryDisplay();
209     shelf_view_ = test::LauncherTestAPI(launcher).shelf_view();
210
211     // The bounds should be big enough for 4 buttons + overflow chevron.
212     shelf_view_->SetBounds(0, 0, 500,
213         internal::ShelfLayoutManager::GetPreferredShelfSize());
214
215     test_api_.reset(new ShelfViewTestAPI(shelf_view_));
216     test_api_->SetAnimationDuration(1);  // Speeds up animation for test.
217
218     item_manager_ =
219         ash::Shell::GetInstance()->launcher_item_delegate_manager();
220     DCHECK(item_manager_);
221
222     // Add browser shortcut launcher item at index 0 for test.
223     AddBrowserShortcut();
224   }
225
226   virtual void TearDown() OVERRIDE {
227     test_api_.reset();
228     AshTestBase::TearDown();
229   }
230
231  protected:
232   void CreateAndSetLauncherItemDelegateForID(LauncherID id) {
233     scoped_ptr<LauncherItemDelegate> delegate(
234         new ash::test::TestLauncherItemDelegate(NULL));
235     item_manager_->SetLauncherItemDelegate(id, delegate.Pass());
236   }
237
238   LauncherID AddBrowserShortcut() {
239     LauncherItem browser_shortcut;
240     browser_shortcut.type = TYPE_BROWSER_SHORTCUT;
241
242     LauncherID id = model_->next_id();
243     model_->AddAt(browser_index_, browser_shortcut);
244     CreateAndSetLauncherItemDelegateForID(id);
245     test_api_->RunMessageLoopUntilAnimationsDone();
246     return id;
247   }
248
249   LauncherID AddAppShortcut() {
250     LauncherItem item;
251     item.type = TYPE_APP_SHORTCUT;
252     item.status = STATUS_CLOSED;
253
254     LauncherID id = model_->next_id();
255     model_->Add(item);
256     CreateAndSetLauncherItemDelegateForID(id);
257     test_api_->RunMessageLoopUntilAnimationsDone();
258     return id;
259   }
260
261   LauncherID AddPanel() {
262     LauncherID id = AddPanelNoWait();
263     test_api_->RunMessageLoopUntilAnimationsDone();
264     return id;
265   }
266
267   LauncherID AddPlatformAppNoWait() {
268     LauncherItem item;
269     item.type = TYPE_PLATFORM_APP;
270     item.status = STATUS_RUNNING;
271
272     LauncherID id = model_->next_id();
273     model_->Add(item);
274     CreateAndSetLauncherItemDelegateForID(id);
275     return id;
276   }
277
278   LauncherID AddPanelNoWait() {
279     LauncherItem item;
280     item.type = TYPE_APP_PANEL;
281     item.status = STATUS_RUNNING;
282
283     LauncherID id = model_->next_id();
284     model_->Add(item);
285     CreateAndSetLauncherItemDelegateForID(id);
286     return id;
287   }
288
289   LauncherID AddPlatformApp() {
290     LauncherID id = AddPlatformAppNoWait();
291     test_api_->RunMessageLoopUntilAnimationsDone();
292     return id;
293   }
294
295   void RemoveByID(LauncherID id) {
296     model_->RemoveItemAt(model_->ItemIndexByID(id));
297     test_api_->RunMessageLoopUntilAnimationsDone();
298   }
299
300   internal::LauncherButton* GetButtonByID(LauncherID id) {
301     int index = model_->ItemIndexByID(id);
302     return test_api_->GetButton(index);
303   }
304
305   LauncherItem GetItemByID(LauncherID id) {
306     LauncherItems::const_iterator items = model_->ItemByID(id);
307     return *items;
308   }
309
310   void CheckModelIDs(
311       const std::vector<std::pair<LauncherID, views::View*> >& id_map) {
312     size_t map_index = 0;
313     for (size_t model_index = 0;
314          model_index < model_->items().size();
315          ++model_index) {
316       ash::LauncherItem item = model_->items()[model_index];
317       ash::LauncherID id = item.id;
318       EXPECT_EQ(id_map[map_index].first, id);
319       EXPECT_EQ(id_map[map_index].second, GetButtonByID(id));
320       ++map_index;
321     }
322     ASSERT_EQ(map_index, id_map.size());
323   }
324
325   void VerifyLauncherItemBoundsAreValid() {
326     for (int i=0;i <= test_api_->GetLastVisibleIndex(); ++i) {
327       if (test_api_->GetButton(i)) {
328         gfx::Rect shelf_view_bounds = shelf_view_->GetLocalBounds();
329         gfx::Rect item_bounds = test_api_->GetBoundsByIndex(i);
330         EXPECT_TRUE(item_bounds.x() >= 0);
331         EXPECT_TRUE(item_bounds.y() >= 0);
332         EXPECT_TRUE(item_bounds.right() <= shelf_view_bounds.width());
333         EXPECT_TRUE(item_bounds.bottom() <= shelf_view_bounds.height());
334       }
335     }
336   }
337
338   views::View* SimulateButtonPressed(
339       internal::LauncherButtonHost::Pointer pointer,
340       int button_index) {
341     internal::LauncherButtonHost* button_host = shelf_view_;
342     views::View* button = test_api_->GetButton(button_index);
343     ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED,
344                                button->bounds().origin(),
345                                button->GetBoundsInScreen().origin(), 0);
346     button_host->PointerPressedOnButton(button, pointer, click_event);
347     return button;
348   }
349
350   views::View* SimulateClick(internal::LauncherButtonHost::Pointer pointer,
351                              int button_index) {
352     internal::LauncherButtonHost* button_host = shelf_view_;
353     views::View* button = SimulateButtonPressed(pointer, button_index);
354     button_host->PointerReleasedOnButton(button,
355                                          internal::LauncherButtonHost::MOUSE,
356                                          false);
357     return button;
358   }
359
360   views::View* SimulateDrag(internal::LauncherButtonHost::Pointer pointer,
361                             int button_index,
362                             int destination_index) {
363     internal::LauncherButtonHost* button_host = shelf_view_;
364     views::View* button = SimulateButtonPressed(pointer, button_index);
365
366     // Drag.
367     views::View* destination = test_api_->GetButton(destination_index);
368     ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
369                               destination->bounds().origin(),
370                               destination->GetBoundsInScreen().origin(), 0);
371     button_host->PointerDraggedOnButton(button, pointer, drag_event);
372     return button;
373   }
374
375   void SetupForDragTest(
376       std::vector<std::pair<LauncherID, views::View*> >* id_map) {
377     // Initialize |id_map| with the automatically-created launcher buttons.
378     for (size_t i = 0; i < model_->items().size(); ++i) {
379       internal::LauncherButton* button = test_api_->GetButton(i);
380       id_map->push_back(std::make_pair(model_->items()[i].id, button));
381     }
382     ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
383
384     // Add 5 app launcher buttons for testing.
385     for (int i = 0; i < 5; ++i) {
386       LauncherID id = AddAppShortcut();
387       // App Icon is located at index 0, and browser shortcut is located at
388       // index 1. So we should start to add app shortcut at index 2.
389       id_map->insert(id_map->begin() + (i + browser_index_ + 1),
390                      std::make_pair(id, GetButtonByID(id)));
391     }
392     ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
393   }
394
395   views::View* GetTooltipAnchorView() {
396     return shelf_view_->tooltip_manager()->anchor_;
397   }
398
399   void ShowTooltip() {
400     shelf_view_->tooltip_manager()->ShowInternal();
401   }
402
403   LauncherModel* model_;
404   internal::ShelfView* shelf_view_;
405   int browser_index_;
406   LauncherItemDelegateManager* item_manager_;
407
408   scoped_ptr<ShelfViewTestAPI> test_api_;
409
410  private:
411   DISALLOW_COPY_AND_ASSIGN(ShelfViewTest);
412 };
413
414 class ShelfViewLegacyShelfLayoutTest : public ShelfViewTest {
415  public:
416   ShelfViewLegacyShelfLayoutTest() : ShelfViewTest() {
417     browser_index_ = 0;
418   }
419
420   virtual ~ShelfViewLegacyShelfLayoutTest() {}
421
422   virtual void SetUp() OVERRIDE {
423     CommandLine::ForCurrentProcess()->AppendSwitch(
424         ash::switches::kAshDisableAlternateShelfLayout);
425     ShelfViewTest::SetUp();
426   }
427
428  private:
429   DISALLOW_COPY_AND_ASSIGN(ShelfViewLegacyShelfLayoutTest);
430 };
431
432 class ScopedTextDirectionChange {
433  public:
434   ScopedTextDirectionChange(bool is_rtl)
435       : is_rtl_(is_rtl) {
436     original_locale_ = l10n_util::GetApplicationLocale(std::string());
437     if (is_rtl_)
438       base::i18n::SetICUDefaultLocale("he");
439     CheckTextDirectionIsCorrect();
440   }
441
442   ~ScopedTextDirectionChange() {
443     if (is_rtl_)
444       base::i18n::SetICUDefaultLocale(original_locale_);
445   }
446
447  private:
448   void CheckTextDirectionIsCorrect() {
449     ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
450   }
451
452   bool is_rtl_;
453   std::string original_locale_;
454 };
455
456 class ShelfViewTextDirectionTest
457     : public ShelfViewTest,
458       public testing::WithParamInterface<bool> {
459  public:
460   ShelfViewTextDirectionTest() : text_direction_change_(GetParam()) {}
461   virtual ~ShelfViewTextDirectionTest() {}
462
463   virtual void SetUp() OVERRIDE {
464     ShelfViewTest::SetUp();
465   }
466
467   virtual void TearDown() OVERRIDE {
468     ShelfViewTest::TearDown();
469   }
470
471  private:
472   ScopedTextDirectionChange text_direction_change_;
473
474   DISALLOW_COPY_AND_ASSIGN(ShelfViewTextDirectionTest);
475 };
476
477 // Checks that the ideal item icon bounds match the view's bounds in the screen
478 // in both LTR and RTL.
479 TEST_P(ShelfViewTextDirectionTest, IdealBoundsOfItemIcon) {
480   LauncherID id = AddPlatformApp();
481   internal::LauncherButton* button = GetButtonByID(id);
482   gfx::Rect item_bounds = button->GetBoundsInScreen();
483   gfx::Point icon_offset = button->GetIconBounds().origin();
484   item_bounds.Offset(icon_offset.OffsetFromOrigin());
485   gfx::Rect ideal_bounds = shelf_view_->GetIdealBoundsOfItemIcon(id);
486   gfx::Point screen_origin;
487   views::View::ConvertPointToScreen(shelf_view_, &screen_origin);
488   ideal_bounds.Offset(screen_origin.x(), screen_origin.y());
489   EXPECT_EQ(item_bounds.x(), ideal_bounds.x());
490   EXPECT_EQ(item_bounds.y(), ideal_bounds.y());
491 }
492
493 // Checks that shelf view contents are considered in the correct drag group.
494 TEST_F(ShelfViewTest, EnforceDragType) {
495   EXPECT_TRUE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_PLATFORM_APP));
496   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_APP_SHORTCUT));
497   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP,
498                                        TYPE_BROWSER_SHORTCUT));
499   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_WINDOWED_APP));
500   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_APP_LIST));
501   EXPECT_FALSE(test_api_->SameDragType(TYPE_PLATFORM_APP, TYPE_APP_PANEL));
502
503   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_SHORTCUT));
504   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_SHORTCUT,
505                                       TYPE_BROWSER_SHORTCUT));
506   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT,
507                                        TYPE_WINDOWED_APP));
508   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_LIST));
509   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_PANEL));
510
511   EXPECT_TRUE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT,
512                                       TYPE_BROWSER_SHORTCUT));
513   EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT,
514                                        TYPE_WINDOWED_APP));
515   EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_APP_LIST));
516   EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_APP_PANEL));
517
518   EXPECT_TRUE(test_api_->SameDragType(TYPE_WINDOWED_APP, TYPE_WINDOWED_APP));
519   EXPECT_FALSE(test_api_->SameDragType(TYPE_WINDOWED_APP, TYPE_APP_LIST));
520   EXPECT_FALSE(test_api_->SameDragType(TYPE_WINDOWED_APP, TYPE_APP_PANEL));
521
522   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_LIST, TYPE_APP_LIST));
523   EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_LIST, TYPE_APP_PANEL));
524
525   EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_PANEL, TYPE_APP_PANEL));
526 }
527
528 // Adds platform app button until overflow and verifies that the last added
529 // platform app button is hidden.
530 TEST_F(ShelfViewTest, AddBrowserUntilOverflow) {
531   // All buttons should be visible.
532   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
533             test_api_->GetButtonCount());
534
535   // Add platform app button until overflow.
536   int items_added = 0;
537   LauncherID last_added = AddPlatformApp();
538   while (!test_api_->IsOverflowButtonVisible()) {
539     // Added button is visible after animation while in this loop.
540     EXPECT_TRUE(GetButtonByID(last_added)->visible());
541
542     last_added = AddPlatformApp();
543     ++items_added;
544     ASSERT_LT(items_added, 10000);
545   }
546
547   // The last added button should be invisible.
548   EXPECT_FALSE(GetButtonByID(last_added)->visible());
549 }
550
551 // Adds one platform app button then adds app shortcut until overflow. Verifies
552 // that the browser button gets hidden on overflow and last added app shortcut
553 // is still visible.
554 TEST_F(ShelfViewTest, AddAppShortcutWithBrowserButtonUntilOverflow) {
555   // All buttons should be visible.
556   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
557             test_api_->GetButtonCount());
558
559   LauncherID browser_button_id = AddPlatformApp();
560
561   // Add app shortcut until overflow.
562   int items_added = 0;
563   LauncherID last_added = AddAppShortcut();
564   while (!test_api_->IsOverflowButtonVisible()) {
565     // Added button is visible after animation while in this loop.
566     EXPECT_TRUE(GetButtonByID(last_added)->visible());
567
568     last_added = AddAppShortcut();
569     ++items_added;
570     ASSERT_LT(items_added, 10000);
571   }
572
573   // And the platform app button is invisible.
574   EXPECT_FALSE(GetButtonByID(browser_button_id)->visible());
575 }
576
577 TEST_F(ShelfViewLegacyShelfLayoutTest,
578        AddAppShortcutWithBrowserButtonUntilOverflow) {
579   // All buttons should be visible.
580   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
581             test_api_->GetButtonCount());
582
583   LauncherID browser_button_id = AddPlatformApp();
584
585   // Add app shortcut until overflow.
586   int items_added = 0;
587   LauncherID last_added = AddAppShortcut();
588   while (!test_api_->IsOverflowButtonVisible()) {
589     // Added button is visible after animation while in this loop.
590     EXPECT_TRUE(GetButtonByID(last_added)->visible());
591
592     last_added = AddAppShortcut();
593     ++items_added;
594     ASSERT_LT(items_added, 10000);
595   }
596
597   // The last added app short button should be visible.
598   EXPECT_TRUE(GetButtonByID(last_added)->visible());
599   // And the platform app button is invisible.
600   EXPECT_FALSE(GetButtonByID(browser_button_id)->visible());
601 }
602
603 TEST_F(ShelfViewTest, AddPanelHidesPlatformAppButton) {
604   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
605             test_api_->GetButtonCount());
606
607   // Add platform app button until overflow, remember last visible platform app
608   // button.
609   int items_added = 0;
610   LauncherID first_added = AddPlatformApp();
611   EXPECT_TRUE(GetButtonByID(first_added)->visible());
612   while (true) {
613     LauncherID added = AddPlatformApp();
614     if (test_api_->IsOverflowButtonVisible()) {
615       EXPECT_FALSE(GetButtonByID(added)->visible());
616       RemoveByID(added);
617       break;
618     }
619     ++items_added;
620     ASSERT_LT(items_added, 10000);
621   }
622
623   LauncherID panel = AddPanel();
624   EXPECT_TRUE(test_api_->IsOverflowButtonVisible());
625
626   RemoveByID(panel);
627   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
628 }
629
630 TEST_F(ShelfViewLegacyShelfLayoutTest, AddPanelHidesPlatformAppButton) {
631   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
632             test_api_->GetButtonCount());
633
634   // Add platform app button until overflow, remember last visible platform app
635   // button.
636   int items_added = 0;
637   LauncherID first_added = AddPlatformApp();
638   EXPECT_TRUE(GetButtonByID(first_added)->visible());
639   LauncherID last_visible = first_added;
640   while (true) {
641     LauncherID added = AddPlatformApp();
642     if (test_api_->IsOverflowButtonVisible()) {
643       EXPECT_FALSE(GetButtonByID(added)->visible());
644       break;
645     }
646     last_visible = added;
647     ++items_added;
648     ASSERT_LT(items_added, 10000);
649   }
650
651   LauncherID panel = AddPanel();
652   EXPECT_TRUE(GetButtonByID(panel)->visible());
653   EXPECT_FALSE(GetButtonByID(last_visible)->visible());
654
655   RemoveByID(panel);
656   EXPECT_TRUE(GetButtonByID(last_visible)->visible());
657 }
658
659 // When there are more panels then platform app buttons we should hide panels
660 // rather than platform apps.
661 TEST_F(ShelfViewTest, PlatformAppHidesExcessPanels) {
662   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
663             test_api_->GetButtonCount());
664
665   // Add platform app button.
666   LauncherID platform_app = AddPlatformApp();
667   LauncherID first_panel = AddPanel();
668
669   EXPECT_TRUE(GetButtonByID(platform_app)->visible());
670   EXPECT_TRUE(GetButtonByID(first_panel)->visible());
671
672   // Add panels until there is an overflow.
673   LauncherID last_panel = first_panel;
674   int items_added = 0;
675   while (!test_api_->IsOverflowButtonVisible()) {
676     last_panel = AddPanel();
677     ++items_added;
678     ASSERT_LT(items_added, 10000);
679   }
680
681   // The first panel should now be hidden by the new platform apps needing
682   // space.
683   EXPECT_FALSE(GetButtonByID(first_panel)->visible());
684   EXPECT_TRUE(GetButtonByID(last_panel)->visible());
685   EXPECT_TRUE(GetButtonByID(platform_app)->visible());
686
687   // Adding platform apps should eventually begin to hide platform apps. We will
688   // add platform apps until either the last panel or platform app is hidden.
689   items_added = 0;
690   while (GetButtonByID(platform_app)->visible() &&
691          GetButtonByID(last_panel)->visible()) {
692     platform_app = AddPlatformApp();
693     ++items_added;
694     ASSERT_LT(items_added, 10000);
695   }
696   EXPECT_TRUE(GetButtonByID(last_panel)->visible());
697   EXPECT_FALSE(GetButtonByID(platform_app)->visible());
698 }
699
700 // Adds button until overflow then removes first added one. Verifies that
701 // the last added one changes from invisible to visible and overflow
702 // chevron is gone.
703 TEST_F(ShelfViewTest, RemoveButtonRevealsOverflowed) {
704   // All buttons should be visible.
705   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
706             test_api_->GetButtonCount());
707
708   // Add platform app buttons until overflow.
709   int items_added = 0;
710   LauncherID first_added = AddPlatformApp();
711   LauncherID last_added = first_added;
712   while (!test_api_->IsOverflowButtonVisible()) {
713     last_added = AddPlatformApp();
714     ++items_added;
715     ASSERT_LT(items_added, 10000);
716   }
717
718   // Expect add more than 1 button. First added is visible and last is not.
719   EXPECT_NE(first_added, last_added);
720   EXPECT_TRUE(GetButtonByID(first_added)->visible());
721   EXPECT_FALSE(GetButtonByID(last_added)->visible());
722
723   // Remove first added.
724   RemoveByID(first_added);
725
726   // Last added button becomes visible and overflow chevron is gone.
727   EXPECT_TRUE(GetButtonByID(last_added)->visible());
728   EXPECT_EQ(1.0f, GetButtonByID(last_added)->layer()->opacity());
729   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
730 }
731
732 // Verifies that remove last overflowed button should hide overflow chevron.
733 TEST_F(ShelfViewTest, RemoveLastOverflowed) {
734   // All buttons should be visible.
735   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
736             test_api_->GetButtonCount());
737
738   // Add platform app button until overflow.
739   int items_added = 0;
740   LauncherID last_added = AddPlatformApp();
741   while (!test_api_->IsOverflowButtonVisible()) {
742     last_added = AddPlatformApp();
743     ++items_added;
744     ASSERT_LT(items_added, 10000);
745   }
746
747   RemoveByID(last_added);
748   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
749 }
750
751 // Adds platform app button without waiting for animation to finish and verifies
752 // that all added buttons are visible.
753 TEST_F(ShelfViewTest, AddButtonQuickly) {
754   // All buttons should be visible.
755   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
756             test_api_->GetButtonCount());
757
758   // Add a few platform buttons quickly without wait for animation.
759   int added_count = 0;
760   while (!test_api_->IsOverflowButtonVisible()) {
761     AddPlatformAppNoWait();
762     ++added_count;
763     ASSERT_LT(added_count, 10000);
764   }
765
766   // ShelfView should be big enough to hold at least 3 new buttons.
767   ASSERT_GE(added_count, 3);
768
769   // Wait for the last animation to finish.
770   test_api_->RunMessageLoopUntilAnimationsDone();
771
772   // Verifies non-overflow buttons are visible.
773   for (int i = 0; i <= test_api_->GetLastVisibleIndex(); ++i) {
774     internal::LauncherButton* button = test_api_->GetButton(i);
775     if (button) {
776       EXPECT_TRUE(button->visible()) << "button index=" << i;
777       EXPECT_EQ(1.0f, button->layer()->opacity()) << "button index=" << i;
778     }
779   }
780 }
781
782 // Check that model changes are handled correctly while a launcher icon is being
783 // dragged.
784 TEST_F(ShelfViewTest, ModelChangesWhileDragging) {
785   internal::LauncherButtonHost* button_host = shelf_view_;
786
787   std::vector<std::pair<LauncherID, views::View*> > id_map;
788   SetupForDragTest(&id_map);
789
790   // Dragging browser shortcut at index 1.
791   EXPECT_TRUE(model_->items()[1].type == TYPE_BROWSER_SHORTCUT);
792   views::View* dragged_button = SimulateDrag(
793       internal::LauncherButtonHost::MOUSE, 1, 3);
794   std::rotate(id_map.begin() + 1,
795               id_map.begin() + 2,
796               id_map.begin() + 4);
797   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
798   button_host->PointerReleasedOnButton(dragged_button,
799                                        internal::LauncherButtonHost::MOUSE,
800                                        false);
801   EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT);
802
803   // Dragging changes model order.
804   dragged_button = SimulateDrag(
805       internal::LauncherButtonHost::MOUSE, 1, 3);
806   std::rotate(id_map.begin() + 1,
807               id_map.begin() + 2,
808               id_map.begin() + 4);
809   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
810
811   // Cancelling the drag operation restores previous order.
812   button_host->PointerReleasedOnButton(dragged_button,
813                                        internal::LauncherButtonHost::MOUSE,
814                                        true);
815   std::rotate(id_map.begin() + 1,
816               id_map.begin() + 3,
817               id_map.begin() + 4);
818   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
819
820   // Deleting an item keeps the remaining intact.
821   dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 1, 3);
822   model_->RemoveItemAt(1);
823   id_map.erase(id_map.begin() + 1);
824   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
825   button_host->PointerReleasedOnButton(dragged_button,
826                                        internal::LauncherButtonHost::MOUSE,
827                                        false);
828
829   // Adding a launcher item cancels the drag and respects the order.
830   dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 1, 3);
831   LauncherID new_id = AddAppShortcut();
832   id_map.insert(id_map.begin() + 6,
833                 std::make_pair(new_id, GetButtonByID(new_id)));
834   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
835   button_host->PointerReleasedOnButton(dragged_button,
836                                        internal::LauncherButtonHost::MOUSE,
837                                        false);
838
839   // Adding a launcher item at the end (i.e. a panel)  canels drag and respects
840   // the order.
841   dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 1, 3);
842   new_id = AddPanel();
843   id_map.insert(id_map.begin() + 7,
844                 std::make_pair(new_id, GetButtonByID(new_id)));
845   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
846   button_host->PointerReleasedOnButton(dragged_button,
847                                        internal::LauncherButtonHost::MOUSE,
848                                        false);
849 }
850
851 TEST_F(ShelfViewLegacyShelfLayoutTest, ModelChangesWhileDragging) {
852   internal::LauncherButtonHost* button_host = shelf_view_;
853
854   std::vector<std::pair<LauncherID, views::View*> > id_map;
855   SetupForDragTest(&id_map);
856
857   // Dragging browser shortcut at index 0.
858   EXPECT_TRUE(model_->items()[0].type == TYPE_BROWSER_SHORTCUT);
859   views::View* dragged_button = SimulateDrag(
860       internal::LauncherButtonHost::MOUSE, 0, 2);
861   std::rotate(id_map.begin(),
862               id_map.begin() + 1,
863               id_map.begin() + 3);
864   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
865   button_host->PointerReleasedOnButton(dragged_button,
866                                        internal::LauncherButtonHost::MOUSE,
867                                        false);
868   EXPECT_TRUE(model_->items()[2].type == TYPE_BROWSER_SHORTCUT);
869
870   // Dragging changes model order.
871   dragged_button = SimulateDrag(
872       internal::LauncherButtonHost::MOUSE, 0, 2);
873   std::rotate(id_map.begin(),
874               id_map.begin() + 1,
875               id_map.begin() + 3);
876   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
877
878   // Cancelling the drag operation restores previous order.
879   button_host->PointerReleasedOnButton(dragged_button,
880                                        internal::LauncherButtonHost::MOUSE,
881                                        true);
882   std::rotate(id_map.begin(),
883               id_map.begin() + 2,
884               id_map.begin() + 3);
885   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
886
887   // Deleting an item keeps the remaining intact.
888   dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
889   model_->RemoveItemAt(1);
890   id_map.erase(id_map.begin() + 1);
891   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
892   button_host->PointerReleasedOnButton(dragged_button,
893                                        internal::LauncherButtonHost::MOUSE,
894                                        false);
895
896   // Adding a launcher item cancels the drag and respects the order.
897   dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
898   LauncherID new_id = AddAppShortcut();
899   id_map.insert(id_map.begin() + 5,
900                 std::make_pair(new_id, GetButtonByID(new_id)));
901   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
902   button_host->PointerReleasedOnButton(dragged_button,
903                                        internal::LauncherButtonHost::MOUSE,
904                                        false);
905
906   // Adding a launcher item at the end (i.e. a panel)  canels drag and respects
907   // the order.
908   dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
909   new_id = AddPanel();
910   id_map.insert(id_map.begin() + 7,
911                 std::make_pair(new_id, GetButtonByID(new_id)));
912   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
913   button_host->PointerReleasedOnButton(dragged_button,
914                                        internal::LauncherButtonHost::MOUSE,
915                                        false);
916 }
917
918 // Check that 2nd drag from the other pointer would be ignored.
919 TEST_F(ShelfViewTest, SimultaneousDrag) {
920   internal::LauncherButtonHost* button_host = shelf_view_;
921
922   std::vector<std::pair<LauncherID, views::View*> > id_map;
923   SetupForDragTest(&id_map);
924
925   // Start a mouse drag.
926   views::View* dragged_button_mouse = SimulateDrag(
927       internal::LauncherButtonHost::MOUSE, 1, 3);
928   std::rotate(id_map.begin() + 1,
929               id_map.begin() + 2,
930               id_map.begin() + 4);
931   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
932   // Attempt a touch drag before the mouse drag finishes.
933   views::View* dragged_button_touch = SimulateDrag(
934       internal::LauncherButtonHost::TOUCH, 4, 2);
935
936   // Nothing changes since 2nd drag is ignored.
937   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
938
939   // Finish the mouse drag.
940   button_host->PointerReleasedOnButton(dragged_button_mouse,
941                                        internal::LauncherButtonHost::MOUSE,
942                                        false);
943   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
944
945   // Now start a touch drag.
946   dragged_button_touch = SimulateDrag(
947       internal::LauncherButtonHost::TOUCH, 4, 2);
948   std::rotate(id_map.begin() + 3,
949               id_map.begin() + 4,
950               id_map.begin() + 5);
951   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
952
953   // And attempt a mouse drag before the touch drag finishes.
954   dragged_button_mouse = SimulateDrag(
955       internal::LauncherButtonHost::MOUSE, 1, 2);
956
957   // Nothing changes since 2nd drag is ignored.
958   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
959
960   button_host->PointerReleasedOnButton(dragged_button_touch,
961                                        internal::LauncherButtonHost::TOUCH,
962                                        false);
963   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
964 }
965
966 // Check that clicking first on one item and then dragging another works as
967 // expected.
968 TEST_F(ShelfViewTest, ClickOneDragAnother) {
969   internal::LauncherButtonHost* button_host = shelf_view_;
970
971   std::vector<std::pair<LauncherID, views::View*> > id_map;
972   SetupForDragTest(&id_map);
973
974   // A click on item 1 is simulated.
975   SimulateClick(internal::LauncherButtonHost::MOUSE, 1);
976
977   // Dragging browser index at 0 should change the model order correctly.
978   EXPECT_TRUE(model_->items()[1].type == TYPE_BROWSER_SHORTCUT);
979   views::View* dragged_button = SimulateDrag(
980       internal::LauncherButtonHost::MOUSE, 1, 3);
981   std::rotate(id_map.begin() + 1,
982               id_map.begin() + 2,
983               id_map.begin() + 4);
984   ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
985   button_host->PointerReleasedOnButton(dragged_button,
986                                        internal::LauncherButtonHost::MOUSE,
987                                        false);
988   EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT);
989 }
990
991 // Confirm that item status changes are reflected in the buttons.
992 TEST_F(ShelfViewTest, LauncherItemStatus) {
993   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
994             test_api_->GetButtonCount());
995
996   // Add platform app button.
997   LauncherID last_added = AddPlatformApp();
998   LauncherItem item = GetItemByID(last_added);
999   int index = model_->ItemIndexByID(last_added);
1000   internal::LauncherButton* button = GetButtonByID(last_added);
1001   ASSERT_EQ(internal::LauncherButton::STATE_RUNNING, button->state());
1002   item.status = ash::STATUS_ACTIVE;
1003   model_->Set(index, item);
1004   ASSERT_EQ(internal::LauncherButton::STATE_ACTIVE, button->state());
1005   item.status = ash::STATUS_ATTENTION;
1006   model_->Set(index, item);
1007   ASSERT_EQ(internal::LauncherButton::STATE_ATTENTION, button->state());
1008 }
1009
1010 TEST_F(ShelfViewLegacyShelfLayoutTest,
1011        LauncherItemPositionReflectedOnStateChanged) {
1012   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1013             test_api_->GetButtonCount());
1014
1015   // Add 2 items to the launcher.
1016   LauncherID item1_id = AddPlatformApp();
1017   LauncherID item2_id = AddPlatformAppNoWait();
1018   internal::LauncherButton* item1_button = GetButtonByID(item1_id);
1019   internal::LauncherButton* item2_button = GetButtonByID(item2_id);
1020
1021   internal::LauncherButton::State state_mask =
1022       static_cast<internal::LauncherButton::State>
1023           (internal::LauncherButton::STATE_NORMAL |
1024           internal::LauncherButton::STATE_HOVERED |
1025           internal::LauncherButton::STATE_RUNNING |
1026           internal::LauncherButton::STATE_ACTIVE |
1027           internal::LauncherButton::STATE_ATTENTION |
1028           internal::LauncherButton::STATE_FOCUSED);
1029
1030   // Clear the button states.
1031   item1_button->ClearState(state_mask);
1032   item2_button->ClearState(state_mask);
1033
1034   // Since default alignment in tests is bottom, state is reflected in y-axis.
1035   ASSERT_EQ(item1_button->GetIconBounds().y(),
1036             item2_button->GetIconBounds().y());
1037   item1_button->AddState(internal::LauncherButton::STATE_HOVERED);
1038   ASSERT_NE(item1_button->GetIconBounds().y(),
1039             item2_button->GetIconBounds().y());
1040   item1_button->ClearState(internal::LauncherButton::STATE_HOVERED);
1041 }
1042
1043 // Confirm that item status changes are reflected in the buttons
1044 // for platform apps.
1045 TEST_F(ShelfViewTest, LauncherItemStatusPlatformApp) {
1046   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1047             test_api_->GetButtonCount());
1048
1049   // Add platform app button.
1050   LauncherID last_added = AddPlatformApp();
1051   LauncherItem item = GetItemByID(last_added);
1052   int index = model_->ItemIndexByID(last_added);
1053   internal::LauncherButton* button = GetButtonByID(last_added);
1054   ASSERT_EQ(internal::LauncherButton::STATE_RUNNING, button->state());
1055   item.status = ash::STATUS_ACTIVE;
1056   model_->Set(index, item);
1057   ASSERT_EQ(internal::LauncherButton::STATE_ACTIVE, button->state());
1058   item.status = ash::STATUS_ATTENTION;
1059   model_->Set(index, item);
1060   ASSERT_EQ(internal::LauncherButton::STATE_ATTENTION, button->state());
1061 }
1062
1063 // Confirm that launcher item bounds are correctly updated on shelf changes.
1064 TEST_F(ShelfViewTest, LauncherItemBoundsCheck) {
1065   VerifyLauncherItemBoundsAreValid();
1066   shelf_view_->shelf_layout_manager()->SetAutoHideBehavior(
1067       SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
1068   test_api_->RunMessageLoopUntilAnimationsDone();
1069   VerifyLauncherItemBoundsAreValid();
1070   shelf_view_->shelf_layout_manager()->SetAutoHideBehavior(
1071       SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
1072   test_api_->RunMessageLoopUntilAnimationsDone();
1073   VerifyLauncherItemBoundsAreValid();
1074 }
1075
1076 TEST_F(ShelfViewTest, ShelfTooltipTest) {
1077   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1078             test_api_->GetButtonCount());
1079
1080   // Prepare some items to the launcher.
1081   LauncherID app_button_id = AddAppShortcut();
1082   LauncherID platform_button_id = AddPlatformApp();
1083
1084   internal::LauncherButton* app_button = GetButtonByID(app_button_id);
1085   internal::LauncherButton* platform_button = GetButtonByID(platform_button_id);
1086
1087   internal::LauncherButtonHost* button_host = shelf_view_;
1088   internal::ShelfTooltipManager* tooltip_manager =
1089       shelf_view_->tooltip_manager();
1090
1091   button_host->MouseEnteredButton(app_button);
1092   // There's a delay to show the tooltip, so it's not visible yet.
1093   EXPECT_FALSE(tooltip_manager->IsVisible());
1094   EXPECT_EQ(app_button, GetTooltipAnchorView());
1095
1096   ShowTooltip();
1097   EXPECT_TRUE(tooltip_manager->IsVisible());
1098
1099   // Once it's visible, it keeps visibility and is pointing to the same
1100   // item.
1101   button_host->MouseExitedButton(app_button);
1102   EXPECT_TRUE(tooltip_manager->IsVisible());
1103   EXPECT_EQ(app_button, GetTooltipAnchorView());
1104
1105   // When entered to another item, it switches to the new item.  There is no
1106   // delay for the visibility.
1107   button_host->MouseEnteredButton(platform_button);
1108   EXPECT_TRUE(tooltip_manager->IsVisible());
1109   EXPECT_EQ(platform_button, GetTooltipAnchorView());
1110
1111   button_host->MouseExitedButton(platform_button);
1112   tooltip_manager->Close();
1113
1114   // Next time: enter app_button -> move immediately to tab_button.
1115   button_host->MouseEnteredButton(app_button);
1116   button_host->MouseExitedButton(app_button);
1117   button_host->MouseEnteredButton(platform_button);
1118   EXPECT_FALSE(tooltip_manager->IsVisible());
1119   EXPECT_EQ(platform_button, GetTooltipAnchorView());
1120 }
1121
1122 // Verify a fix for crash caused by a tooltip update for a deleted launcher
1123 // button, see crbug.com/288838.
1124 TEST_F(ShelfViewTest, RemovingItemClosesTooltip) {
1125   internal::LauncherButtonHost* button_host = shelf_view_;
1126   internal::ShelfTooltipManager* tooltip_manager =
1127       shelf_view_->tooltip_manager();
1128
1129   // Add an item to the launcher.
1130   LauncherID app_button_id = AddAppShortcut();
1131   internal::LauncherButton* app_button = GetButtonByID(app_button_id);
1132
1133   // Spawn a tooltip on that item.
1134   button_host->MouseEnteredButton(app_button);
1135   ShowTooltip();
1136   EXPECT_TRUE(tooltip_manager->IsVisible());
1137
1138   // Remove the app shortcut while the tooltip is open. The tooltip should be
1139   // closed.
1140   RemoveByID(app_button_id);
1141   EXPECT_FALSE(tooltip_manager->IsVisible());
1142
1143   // Change the shelf layout. This should not crash.
1144   ash::Shell::GetInstance()->SetShelfAlignment(
1145       ash::SHELF_ALIGNMENT_LEFT,
1146       ash::Shell::GetPrimaryRootWindow());
1147 }
1148
1149 // Changing the shelf alignment closes any open tooltip.
1150 TEST_F(ShelfViewTest, ShelfAlignmentClosesTooltip) {
1151   internal::LauncherButtonHost* button_host = shelf_view_;
1152   internal::ShelfTooltipManager* tooltip_manager =
1153       shelf_view_->tooltip_manager();
1154
1155   // Add an item to the launcher.
1156   LauncherID app_button_id = AddAppShortcut();
1157   internal::LauncherButton* app_button = GetButtonByID(app_button_id);
1158
1159   // Spawn a tooltip on the item.
1160   button_host->MouseEnteredButton(app_button);
1161   ShowTooltip();
1162   EXPECT_TRUE(tooltip_manager->IsVisible());
1163
1164   // Changing shelf alignment hides the tooltip.
1165   ash::Shell::GetInstance()->SetShelfAlignment(
1166       ash::SHELF_ALIGNMENT_LEFT,
1167       ash::Shell::GetPrimaryRootWindow());
1168   EXPECT_FALSE(tooltip_manager->IsVisible());
1169 }
1170
1171 TEST_F(ShelfViewTest, ShouldHideTooltipTest) {
1172   LauncherID app_button_id = AddAppShortcut();
1173   LauncherID platform_button_id = AddPlatformApp();
1174
1175   // The tooltip shouldn't hide if the mouse is on normal buttons.
1176   for (int i = 0; i < test_api_->GetButtonCount(); i++) {
1177     internal::LauncherButton* button = test_api_->GetButton(i);
1178     if (!button)
1179       continue;
1180
1181     EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1182         button->GetMirroredBounds().CenterPoint()))
1183         << "ShelfView tries to hide on button " << i;
1184   }
1185
1186   // The tooltip should not hide on the app-list button.
1187   views::View* app_list_button = shelf_view_->GetAppListButtonView();
1188   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1189       app_list_button->GetMirroredBounds().CenterPoint()));
1190
1191   // The tooltip shouldn't hide if the mouse is in the gap between two buttons.
1192   gfx::Rect app_button_rect = GetButtonByID(app_button_id)->GetMirroredBounds();
1193   gfx::Rect platform_button_rect =
1194       GetButtonByID(platform_button_id)->GetMirroredBounds();
1195   ASSERT_FALSE(app_button_rect.Intersects(platform_button_rect));
1196   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1197       gfx::UnionRects(app_button_rect, platform_button_rect).CenterPoint()));
1198
1199   // The tooltip should hide if it's outside of all buttons.
1200   gfx::Rect all_area;
1201   for (int i = 0; i < test_api_->GetButtonCount(); i++) {
1202     internal::LauncherButton* button = test_api_->GetButton(i);
1203     if (!button)
1204       continue;
1205
1206     all_area.Union(button->GetMirroredBounds());
1207   }
1208   all_area.Union(shelf_view_->GetAppListButtonView()->GetMirroredBounds());
1209   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(all_area.origin()));
1210   EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1211       gfx::Point(all_area.right() - 1, all_area.bottom() - 1)));
1212   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
1213       gfx::Point(all_area.right(), all_area.y())));
1214   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
1215       gfx::Point(all_area.x() - 1, all_area.y())));
1216   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
1217       gfx::Point(all_area.x(), all_area.y() - 1)));
1218   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
1219       gfx::Point(all_area.x(), all_area.bottom())));
1220 }
1221
1222 TEST_F(ShelfViewTest, ShouldHideTooltipWithAppListWindowTest) {
1223   Shell::GetInstance()->ToggleAppList(NULL);
1224   ASSERT_TRUE(Shell::GetInstance()->GetAppListWindow());
1225
1226   // The tooltip shouldn't hide if the mouse is on normal buttons.
1227   for (int i = 1; i < test_api_->GetButtonCount(); i++) {
1228     internal::LauncherButton* button = test_api_->GetButton(i);
1229     if (!button)
1230       continue;
1231
1232     EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1233         button->GetMirroredBounds().CenterPoint()))
1234         << "ShelfView tries to hide on button " << i;
1235   }
1236
1237   // The tooltip should hide on the app-list button.
1238   views::View* app_list_button = shelf_view_->GetAppListButtonView();
1239   EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
1240       app_list_button->GetMirroredBounds().CenterPoint()));
1241 }
1242
1243 // Test that by moving the mouse cursor off the button onto the bubble it closes
1244 // the bubble.
1245 TEST_F(ShelfViewTest, ShouldHideTooltipWhenHoveringOnTooltip) {
1246   internal::ShelfTooltipManager* tooltip_manager =
1247       shelf_view_->tooltip_manager();
1248   tooltip_manager->CreateZeroDelayTimerForTest();
1249   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
1250
1251   // Move the mouse off any item and check that no tooltip is shown.
1252   generator.MoveMouseTo(gfx::Point(0, 0));
1253   EXPECT_FALSE(tooltip_manager->IsVisible());
1254
1255   // Move the mouse over the button and check that it is visible.
1256   views::View* app_list_button = shelf_view_->GetAppListButtonView();
1257   gfx::Rect bounds = app_list_button->GetBoundsInScreen();
1258   generator.MoveMouseTo(bounds.CenterPoint());
1259   // Wait for the timer to go off.
1260   RunAllPendingInMessageLoop();
1261   EXPECT_TRUE(tooltip_manager->IsVisible());
1262
1263   // Move the mouse cursor slightly to the right of the item. The tooltip should
1264   // stay open.
1265   generator.MoveMouseBy(bounds.width() / 2 + 5, 0);
1266   // Make sure there is no delayed close.
1267   RunAllPendingInMessageLoop();
1268   EXPECT_TRUE(tooltip_manager->IsVisible());
1269
1270   // Move back - it should still stay open.
1271   generator.MoveMouseBy(-(bounds.width() / 2 + 5), 0);
1272   // Make sure there is no delayed close.
1273   RunAllPendingInMessageLoop();
1274   EXPECT_TRUE(tooltip_manager->IsVisible());
1275
1276   // Now move the mouse cursor slightly above the item - so that it is over the
1277   // tooltip bubble. Now it should disappear.
1278   generator.MoveMouseBy(0, -(bounds.height() / 2 + 5));
1279   // Wait until the delayed close kicked in.
1280   RunAllPendingInMessageLoop();
1281   EXPECT_FALSE(tooltip_manager->IsVisible());
1282 }
1283
1284 // Resizing shelf view while an add animation without fade-in is running,
1285 // which happens when overflow happens. App list button should end up in its
1286 // new ideal bounds.
1287 TEST_F(ShelfViewTest, ResizeDuringOverflowAddAnimation) {
1288   // All buttons should be visible.
1289   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1290             test_api_->GetButtonCount());
1291
1292   // Add buttons until overflow. Let the non-overflow add animations finish but
1293   // leave the last running.
1294   int items_added = 0;
1295   AddPlatformAppNoWait();
1296   while (!test_api_->IsOverflowButtonVisible()) {
1297     test_api_->RunMessageLoopUntilAnimationsDone();
1298     AddPlatformAppNoWait();
1299     ++items_added;
1300     ASSERT_LT(items_added, 10000);
1301   }
1302
1303   // Resize shelf view with that animation running and stay overflown.
1304   gfx::Rect bounds = shelf_view_->bounds();
1305   bounds.set_width(bounds.width() - kLauncherPreferredSize);
1306   shelf_view_->SetBoundsRect(bounds);
1307   ASSERT_TRUE(test_api_->IsOverflowButtonVisible());
1308
1309   // Finish the animation.
1310   test_api_->RunMessageLoopUntilAnimationsDone();
1311
1312   // App list button should ends up in its new ideal bounds.
1313   const int app_list_button_index = test_api_->GetButtonCount() - 1;
1314   const gfx::Rect& app_list_ideal_bounds =
1315       test_api_->GetIdealBoundsByIndex(app_list_button_index);
1316   const gfx::Rect& app_list_bounds =
1317       test_api_->GetBoundsByIndex(app_list_button_index);
1318   EXPECT_EQ(app_list_bounds, app_list_ideal_bounds);
1319 }
1320
1321 // Check that the first item in the list follows Fitt's law by including the
1322 // first pixel and being therefore bigger then the others.
1323 TEST_F(ShelfViewLegacyShelfLayoutTest, CheckFittsLaw) {
1324   // All buttons should be visible.
1325   ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1326             test_api_->GetButtonCount());
1327   gfx::Rect ideal_bounds_0 = test_api_->GetIdealBoundsByIndex(0);
1328   gfx::Rect ideal_bounds_1 = test_api_->GetIdealBoundsByIndex(1);
1329   EXPECT_GT(ideal_bounds_0.width(), ideal_bounds_1.width());
1330 }
1331
1332 class ShelfViewVisibleBoundsTest : public ShelfViewTest,
1333                                       public testing::WithParamInterface<bool> {
1334  public:
1335   ShelfViewVisibleBoundsTest() : text_direction_change_(GetParam()) {}
1336
1337   void CheckAllItemsAreInBounds() {
1338     gfx::Rect visible_bounds = shelf_view_->GetVisibleItemsBoundsInScreen();
1339     gfx::Rect launcher_bounds = shelf_view_->GetBoundsInScreen();
1340     EXPECT_TRUE(launcher_bounds.Contains(visible_bounds));
1341     for (int i = 0; i < test_api_->GetButtonCount(); ++i)
1342       if (internal::LauncherButton* button = test_api_->GetButton(i))
1343         EXPECT_TRUE(visible_bounds.Contains(button->GetBoundsInScreen()));
1344     CheckAppListButtonIsInBounds();
1345   }
1346
1347   void CheckAppListButtonIsInBounds() {
1348     gfx::Rect visible_bounds = shelf_view_->GetVisibleItemsBoundsInScreen();
1349     gfx::Rect app_list_button_bounds = shelf_view_->GetAppListButtonView()->
1350        GetBoundsInScreen();
1351     EXPECT_TRUE(visible_bounds.Contains(app_list_button_bounds));
1352   }
1353
1354  private:
1355   ScopedTextDirectionChange text_direction_change_;
1356
1357   DISALLOW_COPY_AND_ASSIGN(ShelfViewVisibleBoundsTest);
1358 };
1359
1360 TEST_P(ShelfViewVisibleBoundsTest, ItemsAreInBounds) {
1361   // Adding elements leaving some empty space.
1362   for (int i = 0; i < 3; i++) {
1363     AddAppShortcut();
1364   }
1365   test_api_->RunMessageLoopUntilAnimationsDone();
1366   EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
1367   CheckAllItemsAreInBounds();
1368   // Same for overflow case.
1369   while (!test_api_->IsOverflowButtonVisible()) {
1370     AddAppShortcut();
1371   }
1372   test_api_->RunMessageLoopUntilAnimationsDone();
1373   CheckAllItemsAreInBounds();
1374 }
1375
1376 INSTANTIATE_TEST_CASE_P(LtrRtl, ShelfViewTextDirectionTest, testing::Bool());
1377 INSTANTIATE_TEST_CASE_P(VisibleBounds, ShelfViewVisibleBoundsTest,
1378     testing::Bool());
1379
1380 }  // namespace test
1381 }  // namespace ash