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.
5 #include "ash/shelf/shelf_view.h"
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"
49 ////////////////////////////////////////////////////////////////////////////////
50 // ShelfIconObserver tests.
52 class TestShelfIconObserver : public ShelfIconObserver {
54 explicit TestShelfIconObserver(Launcher* launcher)
55 : launcher_(launcher),
56 change_notified_(false) {
58 launcher_->AddIconObserver(this);
61 virtual ~TestShelfIconObserver() {
63 launcher_->RemoveIconObserver(this);
66 // ShelfIconObserver implementation.
67 virtual void OnShelfIconPositionsChanged() OVERRIDE {
68 change_notified_ = true;
71 int change_notified() const { return change_notified_; }
72 void Reset() { change_notified_ = false; }
76 bool change_notified_;
78 DISALLOW_COPY_AND_ASSIGN(TestShelfIconObserver);
81 class ShelfViewIconObserverTest : public ash::test::AshTestBase {
83 ShelfViewIconObserverTest() {}
84 virtual ~ShelfViewIconObserverTest() {}
86 virtual void SetUp() OVERRIDE {
88 Launcher* launcher = Launcher::ForPrimaryDisplay();
89 observer_.reset(new TestShelfIconObserver(launcher));
91 shelf_view_test_.reset(new ShelfViewTestAPI(
92 LauncherTestAPI(launcher).shelf_view()));
93 shelf_view_test_->SetAnimationDuration(1);
96 virtual void TearDown() OVERRIDE {
98 AshTestBase::TearDown();
101 TestShelfIconObserver* observer() { return observer_.get(); }
103 ShelfViewTestAPI* shelf_view_test() {
104 return shelf_view_test_.get();
107 Launcher* LauncherForSecondaryDisplay() {
108 return Launcher::ForWindow(Shell::GetAllRootWindows()[1]);
112 scoped_ptr<TestShelfIconObserver> observer_;
113 scoped_ptr<ShelfViewTestAPI> shelf_view_test_;
115 DISALLOW_COPY_AND_ASSIGN(ShelfViewIconObserverTest);
118 TEST_F(ShelfViewIconObserverTest, AddRemove) {
119 ash::test::TestLauncherDelegate* launcher_delegate =
120 ash::test::TestLauncherDelegate::instance();
121 ASSERT_TRUE(launcher_delegate);
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();
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());
136 widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
137 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
138 EXPECT_TRUE(observer()->change_notified());
142 // Sometimes fails on trybots on win7_aura. http://crbug.com/177135
144 #define MAYBE_AddRemoveWithMultipleDisplays \
145 DISABLED_AddRemoveWithMultipleDisplays
147 #define MAYBE_AddRemoveWithMultipleDisplays \
148 AddRemoveWithMultipleDisplays
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());
156 ash::test::TestLauncherDelegate* launcher_delegate =
157 ash::test::TestLauncherDelegate::instance();
158 ASSERT_TRUE(launcher_delegate);
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();
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());
172 second_observer.Reset();
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());
180 second_observer.Reset();
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());
196 ////////////////////////////////////////////////////////////////////////////////
199 class ShelfViewTest : public AshTestBase {
201 ShelfViewTest() : model_(NULL), shelf_view_(NULL), browser_index_(1) {}
202 virtual ~ShelfViewTest() {}
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();
211 // The bounds should be big enough for 4 buttons + overflow chevron.
212 shelf_view_->SetBounds(0, 0, 500,
213 internal::ShelfLayoutManager::GetPreferredShelfSize());
215 test_api_.reset(new ShelfViewTestAPI(shelf_view_));
216 test_api_->SetAnimationDuration(1); // Speeds up animation for test.
219 ash::Shell::GetInstance()->launcher_item_delegate_manager();
220 DCHECK(item_manager_);
222 // Add browser shortcut launcher item at index 0 for test.
223 AddBrowserShortcut();
226 virtual void TearDown() OVERRIDE {
228 AshTestBase::TearDown();
232 void CreateAndSetLauncherItemDelegateForID(LauncherID id) {
233 scoped_ptr<LauncherItemDelegate> delegate(
234 new ash::test::TestLauncherItemDelegate(NULL));
235 item_manager_->SetLauncherItemDelegate(id, delegate.Pass());
238 LauncherID AddBrowserShortcut() {
239 LauncherItem browser_shortcut;
240 browser_shortcut.type = TYPE_BROWSER_SHORTCUT;
242 LauncherID id = model_->next_id();
243 model_->AddAt(browser_index_, browser_shortcut);
244 CreateAndSetLauncherItemDelegateForID(id);
245 test_api_->RunMessageLoopUntilAnimationsDone();
249 LauncherID AddAppShortcut() {
251 item.type = TYPE_APP_SHORTCUT;
252 item.status = STATUS_CLOSED;
254 LauncherID id = model_->next_id();
256 CreateAndSetLauncherItemDelegateForID(id);
257 test_api_->RunMessageLoopUntilAnimationsDone();
261 LauncherID AddPanel() {
262 LauncherID id = AddPanelNoWait();
263 test_api_->RunMessageLoopUntilAnimationsDone();
267 LauncherID AddPlatformAppNoWait() {
269 item.type = TYPE_PLATFORM_APP;
270 item.status = STATUS_RUNNING;
272 LauncherID id = model_->next_id();
274 CreateAndSetLauncherItemDelegateForID(id);
278 LauncherID AddPanelNoWait() {
280 item.type = TYPE_APP_PANEL;
281 item.status = STATUS_RUNNING;
283 LauncherID id = model_->next_id();
285 CreateAndSetLauncherItemDelegateForID(id);
289 LauncherID AddPlatformApp() {
290 LauncherID id = AddPlatformAppNoWait();
291 test_api_->RunMessageLoopUntilAnimationsDone();
295 void RemoveByID(LauncherID id) {
296 model_->RemoveItemAt(model_->ItemIndexByID(id));
297 test_api_->RunMessageLoopUntilAnimationsDone();
300 internal::LauncherButton* GetButtonByID(LauncherID id) {
301 int index = model_->ItemIndexByID(id);
302 return test_api_->GetButton(index);
305 LauncherItem GetItemByID(LauncherID id) {
306 LauncherItems::const_iterator items = model_->ItemByID(id);
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();
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));
322 ASSERT_EQ(map_index, id_map.size());
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());
338 views::View* SimulateButtonPressed(
339 internal::LauncherButtonHost::Pointer pointer,
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);
350 views::View* SimulateClick(internal::LauncherButtonHost::Pointer pointer,
352 internal::LauncherButtonHost* button_host = shelf_view_;
353 views::View* button = SimulateButtonPressed(pointer, button_index);
354 button_host->PointerReleasedOnButton(button,
355 internal::LauncherButtonHost::MOUSE,
360 views::View* SimulateDrag(internal::LauncherButtonHost::Pointer pointer,
362 int destination_index) {
363 internal::LauncherButtonHost* button_host = shelf_view_;
364 views::View* button = SimulateButtonPressed(pointer, button_index);
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);
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));
382 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
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)));
392 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
395 views::View* GetTooltipAnchorView() {
396 return shelf_view_->tooltip_manager()->anchor_;
400 shelf_view_->tooltip_manager()->ShowInternal();
403 LauncherModel* model_;
404 internal::ShelfView* shelf_view_;
406 LauncherItemDelegateManager* item_manager_;
408 scoped_ptr<ShelfViewTestAPI> test_api_;
411 DISALLOW_COPY_AND_ASSIGN(ShelfViewTest);
414 class ShelfViewLegacyShelfLayoutTest : public ShelfViewTest {
416 ShelfViewLegacyShelfLayoutTest() : ShelfViewTest() {
420 virtual ~ShelfViewLegacyShelfLayoutTest() {}
422 virtual void SetUp() OVERRIDE {
423 CommandLine::ForCurrentProcess()->AppendSwitch(
424 ash::switches::kAshDisableAlternateShelfLayout);
425 ShelfViewTest::SetUp();
429 DISALLOW_COPY_AND_ASSIGN(ShelfViewLegacyShelfLayoutTest);
432 class ScopedTextDirectionChange {
434 ScopedTextDirectionChange(bool is_rtl)
436 original_locale_ = l10n_util::GetApplicationLocale(std::string());
438 base::i18n::SetICUDefaultLocale("he");
439 CheckTextDirectionIsCorrect();
442 ~ScopedTextDirectionChange() {
444 base::i18n::SetICUDefaultLocale(original_locale_);
448 void CheckTextDirectionIsCorrect() {
449 ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
453 std::string original_locale_;
456 class ShelfViewTextDirectionTest
457 : public ShelfViewTest,
458 public testing::WithParamInterface<bool> {
460 ShelfViewTextDirectionTest() : text_direction_change_(GetParam()) {}
461 virtual ~ShelfViewTextDirectionTest() {}
463 virtual void SetUp() OVERRIDE {
464 ShelfViewTest::SetUp();
467 virtual void TearDown() OVERRIDE {
468 ShelfViewTest::TearDown();
472 ScopedTextDirectionChange text_direction_change_;
474 DISALLOW_COPY_AND_ASSIGN(ShelfViewTextDirectionTest);
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());
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));
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,
508 EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_LIST));
509 EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_SHORTCUT, TYPE_APP_PANEL));
511 EXPECT_TRUE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT,
512 TYPE_BROWSER_SHORTCUT));
513 EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT,
515 EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_APP_LIST));
516 EXPECT_FALSE(test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_APP_PANEL));
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));
522 EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_LIST, TYPE_APP_LIST));
523 EXPECT_FALSE(test_api_->SameDragType(TYPE_APP_LIST, TYPE_APP_PANEL));
525 EXPECT_TRUE(test_api_->SameDragType(TYPE_APP_PANEL, TYPE_APP_PANEL));
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());
535 // Add platform app button until overflow.
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());
542 last_added = AddPlatformApp();
544 ASSERT_LT(items_added, 10000);
547 // The last added button should be invisible.
548 EXPECT_FALSE(GetButtonByID(last_added)->visible());
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
554 TEST_F(ShelfViewTest, AddAppShortcutWithBrowserButtonUntilOverflow) {
555 // All buttons should be visible.
556 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
557 test_api_->GetButtonCount());
559 LauncherID browser_button_id = AddPlatformApp();
561 // Add app shortcut until overflow.
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());
568 last_added = AddAppShortcut();
570 ASSERT_LT(items_added, 10000);
573 // And the platform app button is invisible.
574 EXPECT_FALSE(GetButtonByID(browser_button_id)->visible());
577 TEST_F(ShelfViewLegacyShelfLayoutTest,
578 AddAppShortcutWithBrowserButtonUntilOverflow) {
579 // All buttons should be visible.
580 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
581 test_api_->GetButtonCount());
583 LauncherID browser_button_id = AddPlatformApp();
585 // Add app shortcut until overflow.
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());
592 last_added = AddAppShortcut();
594 ASSERT_LT(items_added, 10000);
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());
603 TEST_F(ShelfViewTest, AddPanelHidesPlatformAppButton) {
604 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
605 test_api_->GetButtonCount());
607 // Add platform app button until overflow, remember last visible platform app
610 LauncherID first_added = AddPlatformApp();
611 EXPECT_TRUE(GetButtonByID(first_added)->visible());
613 LauncherID added = AddPlatformApp();
614 if (test_api_->IsOverflowButtonVisible()) {
615 EXPECT_FALSE(GetButtonByID(added)->visible());
620 ASSERT_LT(items_added, 10000);
623 LauncherID panel = AddPanel();
624 EXPECT_TRUE(test_api_->IsOverflowButtonVisible());
627 EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
630 TEST_F(ShelfViewLegacyShelfLayoutTest, AddPanelHidesPlatformAppButton) {
631 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
632 test_api_->GetButtonCount());
634 // Add platform app button until overflow, remember last visible platform app
637 LauncherID first_added = AddPlatformApp();
638 EXPECT_TRUE(GetButtonByID(first_added)->visible());
639 LauncherID last_visible = first_added;
641 LauncherID added = AddPlatformApp();
642 if (test_api_->IsOverflowButtonVisible()) {
643 EXPECT_FALSE(GetButtonByID(added)->visible());
646 last_visible = added;
648 ASSERT_LT(items_added, 10000);
651 LauncherID panel = AddPanel();
652 EXPECT_TRUE(GetButtonByID(panel)->visible());
653 EXPECT_FALSE(GetButtonByID(last_visible)->visible());
656 EXPECT_TRUE(GetButtonByID(last_visible)->visible());
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());
665 // Add platform app button.
666 LauncherID platform_app = AddPlatformApp();
667 LauncherID first_panel = AddPanel();
669 EXPECT_TRUE(GetButtonByID(platform_app)->visible());
670 EXPECT_TRUE(GetButtonByID(first_panel)->visible());
672 // Add panels until there is an overflow.
673 LauncherID last_panel = first_panel;
675 while (!test_api_->IsOverflowButtonVisible()) {
676 last_panel = AddPanel();
678 ASSERT_LT(items_added, 10000);
681 // The first panel should now be hidden by the new platform apps needing
683 EXPECT_FALSE(GetButtonByID(first_panel)->visible());
684 EXPECT_TRUE(GetButtonByID(last_panel)->visible());
685 EXPECT_TRUE(GetButtonByID(platform_app)->visible());
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.
690 while (GetButtonByID(platform_app)->visible() &&
691 GetButtonByID(last_panel)->visible()) {
692 platform_app = AddPlatformApp();
694 ASSERT_LT(items_added, 10000);
696 EXPECT_TRUE(GetButtonByID(last_panel)->visible());
697 EXPECT_FALSE(GetButtonByID(platform_app)->visible());
700 // Adds button until overflow then removes first added one. Verifies that
701 // the last added one changes from invisible to visible and overflow
703 TEST_F(ShelfViewTest, RemoveButtonRevealsOverflowed) {
704 // All buttons should be visible.
705 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
706 test_api_->GetButtonCount());
708 // Add platform app buttons until overflow.
710 LauncherID first_added = AddPlatformApp();
711 LauncherID last_added = first_added;
712 while (!test_api_->IsOverflowButtonVisible()) {
713 last_added = AddPlatformApp();
715 ASSERT_LT(items_added, 10000);
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());
723 // Remove first added.
724 RemoveByID(first_added);
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());
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());
738 // Add platform app button until overflow.
740 LauncherID last_added = AddPlatformApp();
741 while (!test_api_->IsOverflowButtonVisible()) {
742 last_added = AddPlatformApp();
744 ASSERT_LT(items_added, 10000);
747 RemoveByID(last_added);
748 EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
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());
758 // Add a few platform buttons quickly without wait for animation.
760 while (!test_api_->IsOverflowButtonVisible()) {
761 AddPlatformAppNoWait();
763 ASSERT_LT(added_count, 10000);
766 // ShelfView should be big enough to hold at least 3 new buttons.
767 ASSERT_GE(added_count, 3);
769 // Wait for the last animation to finish.
770 test_api_->RunMessageLoopUntilAnimationsDone();
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);
776 EXPECT_TRUE(button->visible()) << "button index=" << i;
777 EXPECT_EQ(1.0f, button->layer()->opacity()) << "button index=" << i;
782 // Check that model changes are handled correctly while a launcher icon is being
784 TEST_F(ShelfViewTest, ModelChangesWhileDragging) {
785 internal::LauncherButtonHost* button_host = shelf_view_;
787 std::vector<std::pair<LauncherID, views::View*> > id_map;
788 SetupForDragTest(&id_map);
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,
797 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
798 button_host->PointerReleasedOnButton(dragged_button,
799 internal::LauncherButtonHost::MOUSE,
801 EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT);
803 // Dragging changes model order.
804 dragged_button = SimulateDrag(
805 internal::LauncherButtonHost::MOUSE, 1, 3);
806 std::rotate(id_map.begin() + 1,
809 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
811 // Cancelling the drag operation restores previous order.
812 button_host->PointerReleasedOnButton(dragged_button,
813 internal::LauncherButtonHost::MOUSE,
815 std::rotate(id_map.begin() + 1,
818 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
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,
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,
839 // Adding a launcher item at the end (i.e. a panel) canels drag and respects
841 dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 1, 3);
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,
851 TEST_F(ShelfViewLegacyShelfLayoutTest, ModelChangesWhileDragging) {
852 internal::LauncherButtonHost* button_host = shelf_view_;
854 std::vector<std::pair<LauncherID, views::View*> > id_map;
855 SetupForDragTest(&id_map);
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(),
864 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
865 button_host->PointerReleasedOnButton(dragged_button,
866 internal::LauncherButtonHost::MOUSE,
868 EXPECT_TRUE(model_->items()[2].type == TYPE_BROWSER_SHORTCUT);
870 // Dragging changes model order.
871 dragged_button = SimulateDrag(
872 internal::LauncherButtonHost::MOUSE, 0, 2);
873 std::rotate(id_map.begin(),
876 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
878 // Cancelling the drag operation restores previous order.
879 button_host->PointerReleasedOnButton(dragged_button,
880 internal::LauncherButtonHost::MOUSE,
882 std::rotate(id_map.begin(),
885 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
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,
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,
906 // Adding a launcher item at the end (i.e. a panel) canels drag and respects
908 dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
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,
918 // Check that 2nd drag from the other pointer would be ignored.
919 TEST_F(ShelfViewTest, SimultaneousDrag) {
920 internal::LauncherButtonHost* button_host = shelf_view_;
922 std::vector<std::pair<LauncherID, views::View*> > id_map;
923 SetupForDragTest(&id_map);
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,
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);
936 // Nothing changes since 2nd drag is ignored.
937 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
939 // Finish the mouse drag.
940 button_host->PointerReleasedOnButton(dragged_button_mouse,
941 internal::LauncherButtonHost::MOUSE,
943 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
945 // Now start a touch drag.
946 dragged_button_touch = SimulateDrag(
947 internal::LauncherButtonHost::TOUCH, 4, 2);
948 std::rotate(id_map.begin() + 3,
951 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
953 // And attempt a mouse drag before the touch drag finishes.
954 dragged_button_mouse = SimulateDrag(
955 internal::LauncherButtonHost::MOUSE, 1, 2);
957 // Nothing changes since 2nd drag is ignored.
958 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
960 button_host->PointerReleasedOnButton(dragged_button_touch,
961 internal::LauncherButtonHost::TOUCH,
963 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
966 // Check that clicking first on one item and then dragging another works as
968 TEST_F(ShelfViewTest, ClickOneDragAnother) {
969 internal::LauncherButtonHost* button_host = shelf_view_;
971 std::vector<std::pair<LauncherID, views::View*> > id_map;
972 SetupForDragTest(&id_map);
974 // A click on item 1 is simulated.
975 SimulateClick(internal::LauncherButtonHost::MOUSE, 1);
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,
984 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
985 button_host->PointerReleasedOnButton(dragged_button,
986 internal::LauncherButtonHost::MOUSE,
988 EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT);
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());
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());
1010 TEST_F(ShelfViewLegacyShelfLayoutTest,
1011 LauncherItemPositionReflectedOnStateChanged) {
1012 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1013 test_api_->GetButtonCount());
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);
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);
1030 // Clear the button states.
1031 item1_button->ClearState(state_mask);
1032 item2_button->ClearState(state_mask);
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);
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());
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());
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();
1076 TEST_F(ShelfViewTest, ShelfTooltipTest) {
1077 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1078 test_api_->GetButtonCount());
1080 // Prepare some items to the launcher.
1081 LauncherID app_button_id = AddAppShortcut();
1082 LauncherID platform_button_id = AddPlatformApp();
1084 internal::LauncherButton* app_button = GetButtonByID(app_button_id);
1085 internal::LauncherButton* platform_button = GetButtonByID(platform_button_id);
1087 internal::LauncherButtonHost* button_host = shelf_view_;
1088 internal::ShelfTooltipManager* tooltip_manager =
1089 shelf_view_->tooltip_manager();
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());
1097 EXPECT_TRUE(tooltip_manager->IsVisible());
1099 // Once it's visible, it keeps visibility and is pointing to the same
1101 button_host->MouseExitedButton(app_button);
1102 EXPECT_TRUE(tooltip_manager->IsVisible());
1103 EXPECT_EQ(app_button, GetTooltipAnchorView());
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());
1111 button_host->MouseExitedButton(platform_button);
1112 tooltip_manager->Close();
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());
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();
1129 // Add an item to the launcher.
1130 LauncherID app_button_id = AddAppShortcut();
1131 internal::LauncherButton* app_button = GetButtonByID(app_button_id);
1133 // Spawn a tooltip on that item.
1134 button_host->MouseEnteredButton(app_button);
1136 EXPECT_TRUE(tooltip_manager->IsVisible());
1138 // Remove the app shortcut while the tooltip is open. The tooltip should be
1140 RemoveByID(app_button_id);
1141 EXPECT_FALSE(tooltip_manager->IsVisible());
1143 // Change the shelf layout. This should not crash.
1144 ash::Shell::GetInstance()->SetShelfAlignment(
1145 ash::SHELF_ALIGNMENT_LEFT,
1146 ash::Shell::GetPrimaryRootWindow());
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();
1155 // Add an item to the launcher.
1156 LauncherID app_button_id = AddAppShortcut();
1157 internal::LauncherButton* app_button = GetButtonByID(app_button_id);
1159 // Spawn a tooltip on the item.
1160 button_host->MouseEnteredButton(app_button);
1162 EXPECT_TRUE(tooltip_manager->IsVisible());
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());
1171 TEST_F(ShelfViewTest, ShouldHideTooltipTest) {
1172 LauncherID app_button_id = AddAppShortcut();
1173 LauncherID platform_button_id = AddPlatformApp();
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);
1181 EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1182 button->GetMirroredBounds().CenterPoint()))
1183 << "ShelfView tries to hide on button " << i;
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()));
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()));
1199 // The tooltip should hide if it's outside of all buttons.
1201 for (int i = 0; i < test_api_->GetButtonCount(); i++) {
1202 internal::LauncherButton* button = test_api_->GetButton(i);
1206 all_area.Union(button->GetMirroredBounds());
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())));
1222 TEST_F(ShelfViewTest, ShouldHideTooltipWithAppListWindowTest) {
1223 Shell::GetInstance()->ToggleAppList(NULL);
1224 ASSERT_TRUE(Shell::GetInstance()->GetAppListWindow());
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);
1232 EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
1233 button->GetMirroredBounds().CenterPoint()))
1234 << "ShelfView tries to hide on button " << i;
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()));
1243 // Test that by moving the mouse cursor off the button onto the bubble it closes
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());
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());
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());
1263 // Move the mouse cursor slightly to the right of the item. The tooltip should
1265 generator.MoveMouseBy(bounds.width() / 2 + 5, 0);
1266 // Make sure there is no delayed close.
1267 RunAllPendingInMessageLoop();
1268 EXPECT_TRUE(tooltip_manager->IsVisible());
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());
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());
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());
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();
1300 ASSERT_LT(items_added, 10000);
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());
1309 // Finish the animation.
1310 test_api_->RunMessageLoopUntilAnimationsDone();
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);
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());
1332 class ShelfViewVisibleBoundsTest : public ShelfViewTest,
1333 public testing::WithParamInterface<bool> {
1335 ShelfViewVisibleBoundsTest() : text_direction_change_(GetParam()) {}
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();
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));
1355 ScopedTextDirectionChange text_direction_change_;
1357 DISALLOW_COPY_AND_ASSIGN(ShelfViewVisibleBoundsTest);
1360 TEST_P(ShelfViewVisibleBoundsTest, ItemsAreInBounds) {
1361 // Adding elements leaving some empty space.
1362 for (int i = 0; i < 3; i++) {
1365 test_api_->RunMessageLoopUntilAnimationsDone();
1366 EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
1367 CheckAllItemsAreInBounds();
1368 // Same for overflow case.
1369 while (!test_api_->IsOverflowButtonVisible()) {
1372 test_api_->RunMessageLoopUntilAnimationsDone();
1373 CheckAllItemsAreInBounds();
1376 INSTANTIATE_TEST_CASE_P(LtrRtl, ShelfViewTextDirectionTest, testing::Bool());
1377 INSTANTIATE_TEST_CASE_P(VisibleBounds, ShelfViewVisibleBoundsTest,