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/launcher/launcher_view.h"
10 #include "ash/launcher/launcher.h"
11 #include "ash/launcher/launcher_button.h"
12 #include "ash/launcher/launcher_icon_observer.h"
13 #include "ash/launcher/launcher_model.h"
14 #include "ash/launcher/launcher_tooltip_manager.h"
15 #include "ash/root_window_controller.h"
16 #include "ash/shelf/shelf_layout_manager.h"
17 #include "ash/shelf/shelf_widget.h"
18 #include "ash/shell.h"
19 #include "ash/shell_window_ids.h"
20 #include "ash/test/ash_test_base.h"
21 #include "ash/test/launcher_view_test_api.h"
22 #include "ash/test/shell_test_api.h"
23 #include "ash/test/test_launcher_delegate.h"
24 #include "base/basictypes.h"
25 #include "base/compiler_specific.h"
26 #include "base/memory/scoped_ptr.h"
27 #include "grit/ash_resources.h"
28 #include "ui/aura/root_window.h"
29 #include "ui/aura/test/aura_test_base.h"
30 #include "ui/aura/window.h"
31 #include "ui/base/events/event.h"
32 #include "ui/base/events/event_constants.h"
33 #include "ui/compositor/layer.h"
34 #include "ui/views/widget/widget.h"
35 #include "ui/views/widget/widget_delegate.h"
38 const int kExpectedAppIndex
= 1;
44 ////////////////////////////////////////////////////////////////////////////////
45 // LauncherIconObserver tests.
47 class TestLauncherIconObserver
: public LauncherIconObserver
{
49 explicit TestLauncherIconObserver(Launcher
* launcher
)
50 : launcher_(launcher
),
51 change_notified_(false) {
53 launcher_
->AddIconObserver(this);
56 virtual ~TestLauncherIconObserver() {
58 launcher_
->RemoveIconObserver(this);
61 // LauncherIconObserver implementation.
62 virtual void OnLauncherIconPositionsChanged() OVERRIDE
{
63 change_notified_
= true;
66 int change_notified() const { return change_notified_
; }
67 void Reset() { change_notified_
= false; }
71 bool change_notified_
;
73 DISALLOW_COPY_AND_ASSIGN(TestLauncherIconObserver
);
76 class LauncherViewIconObserverTest
: public ash::test::AshTestBase
{
78 LauncherViewIconObserverTest() {}
79 virtual ~LauncherViewIconObserverTest() {}
81 virtual void SetUp() OVERRIDE
{
83 Launcher
* launcher
= Launcher::ForPrimaryDisplay();
84 observer_
.reset(new TestLauncherIconObserver(launcher
));
86 launcher_view_test_
.reset(new LauncherViewTestAPI(
87 launcher
->GetLauncherViewForTest()));
88 launcher_view_test_
->SetAnimationDuration(1);
91 virtual void TearDown() OVERRIDE
{
93 AshTestBase::TearDown();
96 TestLauncherIconObserver
* observer() { return observer_
.get(); }
98 LauncherViewTestAPI
* launcher_view_test() {
99 return launcher_view_test_
.get();
102 Launcher
* LauncherForSecondaryDisplay() {
103 return Launcher::ForWindow(Shell::GetAllRootWindows()[1]);
107 scoped_ptr
<TestLauncherIconObserver
> observer_
;
108 scoped_ptr
<LauncherViewTestAPI
> launcher_view_test_
;
110 DISALLOW_COPY_AND_ASSIGN(LauncherViewIconObserverTest
);
113 TEST_F(LauncherViewIconObserverTest
, AddRemove
) {
114 ash::test::TestLauncherDelegate
* launcher_delegate
=
115 ash::test::TestLauncherDelegate::instance();
116 ASSERT_TRUE(launcher_delegate
);
118 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
119 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
120 params
.bounds
= gfx::Rect(0, 0, 200, 200);
121 params
.context
= CurrentContext();
123 scoped_ptr
<views::Widget
> widget(new views::Widget());
124 widget
->Init(params
);
125 launcher_delegate
->AddLauncherItem(widget
->GetNativeWindow());
126 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
127 EXPECT_TRUE(observer()->change_notified());
131 widget
->GetNativeWindow()->parent()->RemoveChild(widget
->GetNativeWindow());
132 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
133 EXPECT_TRUE(observer()->change_notified());
137 // Sometimes fails on trybots on win7_aura. http://crbug.com/177135
139 #define MAYBE_AddRemoveWithMultipleDisplays \
140 DISABLED_AddRemoveWithMultipleDisplays
142 #define MAYBE_AddRemoveWithMultipleDisplays \
143 AddRemoveWithMultipleDisplays
145 // Make sure creating/deleting an window on one displays notifies a
146 // launcher on external display as well as one on primary.
147 TEST_F(LauncherViewIconObserverTest
, MAYBE_AddRemoveWithMultipleDisplays
) {
148 UpdateDisplay("400x400,400x400");
149 TestLauncherIconObserver
second_observer(LauncherForSecondaryDisplay());
151 ash::test::TestLauncherDelegate
* launcher_delegate
=
152 ash::test::TestLauncherDelegate::instance();
153 ASSERT_TRUE(launcher_delegate
);
155 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
156 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
157 params
.bounds
= gfx::Rect(0, 0, 200, 200);
158 params
.context
= CurrentContext();
160 scoped_ptr
<views::Widget
> widget(new views::Widget());
161 widget
->Init(params
);
162 launcher_delegate
->AddLauncherItem(widget
->GetNativeWindow());
163 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
164 EXPECT_TRUE(observer()->change_notified());
165 EXPECT_TRUE(second_observer
.change_notified());
167 second_observer
.Reset();
169 widget
->GetNativeWindow()->parent()->RemoveChild(widget
->GetNativeWindow());
170 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
171 EXPECT_TRUE(observer()->change_notified());
172 EXPECT_TRUE(second_observer
.change_notified());
175 second_observer
.Reset();
178 TEST_F(LauncherViewIconObserverTest
, BoundsChanged
) {
179 ash::ShelfWidget
* shelf
= Shell::GetPrimaryRootWindowController()->shelf();
180 Launcher
* launcher
= Launcher::ForPrimaryDisplay();
181 gfx::Size shelf_size
=
182 shelf
->GetWindowBoundsInScreen().size();
183 shelf_size
.set_width(shelf_size
.width() / 2);
184 ASSERT_GT(shelf_size
.width(), 0);
185 launcher
->SetLauncherViewBounds(gfx::Rect(shelf_size
));
186 // No animation happens for LauncherView bounds change.
187 EXPECT_TRUE(observer()->change_notified());
191 ////////////////////////////////////////////////////////////////////////////////
192 // LauncherView tests.
194 class LauncherViewTest
: public AshTestBase
{
196 LauncherViewTest() : model_(NULL
), launcher_view_(NULL
) {}
197 virtual ~LauncherViewTest() {}
199 virtual void SetUp() OVERRIDE
{
200 AshTestBase::SetUp();
201 test::ShellTestApi
test_api(Shell::GetInstance());
202 model_
= test_api
.launcher_model();
203 Launcher
* launcher
= Launcher::ForPrimaryDisplay();
204 launcher_view_
= launcher
->GetLauncherViewForTest();
206 // The bounds should be big enough for 4 buttons + overflow chevron.
207 launcher_view_
->SetBounds(0, 0, 500, 50);
209 test_api_
.reset(new LauncherViewTestAPI(launcher_view_
));
210 test_api_
->SetAnimationDuration(1); // Speeds up animation for test.
213 virtual void TearDown() OVERRIDE
{
215 AshTestBase::TearDown();
219 LauncherID
AddAppShortcut() {
221 item
.type
= TYPE_APP_SHORTCUT
;
222 item
.status
= STATUS_CLOSED
;
224 LauncherID id
= model_
->next_id();
226 test_api_
->RunMessageLoopUntilAnimationsDone();
230 LauncherID
AddTabbedBrowserNoWait() {
232 item
.type
= TYPE_TABBED
;
233 item
.status
= STATUS_RUNNING
;
235 LauncherID id
= model_
->next_id();
240 LauncherID
AddTabbedBrowser() {
241 LauncherID id
= AddTabbedBrowserNoWait();
242 test_api_
->RunMessageLoopUntilAnimationsDone();
246 LauncherID
AddPanel() {
247 LauncherID id
= AddPanelNoWait();
248 test_api_
->RunMessageLoopUntilAnimationsDone();
252 LauncherID
AddPlatformAppNoWait() {
254 item
.type
= TYPE_PLATFORM_APP
;
255 item
.status
= STATUS_RUNNING
;
257 LauncherID id
= model_
->next_id();
262 LauncherID
AddPanelNoWait() {
264 item
.type
= TYPE_APP_PANEL
;
265 item
.status
= STATUS_RUNNING
;
267 LauncherID id
= model_
->next_id();
272 LauncherID
AddPlatformApp() {
273 LauncherID id
= AddPlatformAppNoWait();
274 test_api_
->RunMessageLoopUntilAnimationsDone();
278 void RemoveByID(LauncherID id
) {
279 model_
->RemoveItemAt(model_
->ItemIndexByID(id
));
280 test_api_
->RunMessageLoopUntilAnimationsDone();
283 internal::LauncherButton
* GetButtonByID(LauncherID id
) {
284 int index
= model_
->ItemIndexByID(id
);
285 return test_api_
->GetButton(index
);
288 LauncherItem
GetItemByID(LauncherID id
) {
289 LauncherItems::const_iterator items
= model_
->ItemByID(id
);
294 const std::vector
<std::pair
<LauncherID
, views::View
*> >& id_map
) {
295 size_t map_index
= 0;
296 for (size_t model_index
= 0;
297 model_index
< model_
->items().size();
299 ash::LauncherItem item
= model_
->items()[model_index
];
300 ash::LauncherID id
= item
.id
;
301 EXPECT_EQ(id_map
[map_index
].first
, id
);
302 EXPECT_EQ(id_map
[map_index
].second
, GetButtonByID(id
));
305 ASSERT_EQ(map_index
, id_map
.size());
308 void VerifyLauncherItemBoundsAreValid() {
309 for (int i
=0;i
<= test_api_
->GetLastVisibleIndex(); ++i
) {
310 if (test_api_
->GetButton(i
)) {
311 gfx::Rect launcher_view_bounds
= launcher_view_
->GetLocalBounds();
312 gfx::Rect item_bounds
= test_api_
->GetBoundsByIndex(i
);
313 EXPECT_TRUE(item_bounds
.x() >= 0);
314 EXPECT_TRUE(item_bounds
.y() >= 0);
315 EXPECT_TRUE(item_bounds
.right() <= launcher_view_bounds
.width());
316 EXPECT_TRUE(item_bounds
.bottom() <= launcher_view_bounds
.height());
321 views::View
* SimulateDrag(internal::LauncherButtonHost::Pointer pointer
,
323 int destination_index
) {
324 // Add kExpectedAppIndex to each button index to allow default icons.
325 internal::LauncherButtonHost
* button_host
= launcher_view_
;
328 views::View
* button
=
329 test_api_
->GetButton(kExpectedAppIndex
+ button_index
);
330 ui::MouseEvent
click_event(ui::ET_MOUSE_PRESSED
,
331 button
->bounds().origin(),
332 button
->bounds().origin(), 0);
333 button_host
->PointerPressedOnButton(button
, pointer
, click_event
);
336 views::View
* destination
=
337 test_api_
->GetButton(kExpectedAppIndex
+ destination_index
);
338 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
,
339 destination
->bounds().origin(),
340 destination
->bounds().origin(), 0);
341 button_host
->PointerDraggedOnButton(button
, pointer
, drag_event
);
345 void SetupForDragTest(
346 std::vector
<std::pair
<LauncherID
, views::View
*> >* id_map
) {
347 // Initialize |id_map| with the automatically-created launcher buttons.
348 for (size_t i
= 0; i
< model_
->items().size(); ++i
) {
349 internal::LauncherButton
* button
= test_api_
->GetButton(i
);
350 id_map
->push_back(std::make_pair(model_
->items()[i
].id
, button
));
352 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map
));
354 // Add 5 app launcher buttons for testing.
355 for (int i
= 0; i
< 5; ++i
) {
356 LauncherID id
= AddAppShortcut();
357 id_map
->insert(id_map
->begin() + (kExpectedAppIndex
+ i
),
358 std::make_pair(id
, GetButtonByID(id
)));
360 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map
));
363 views::View
* GetTooltipAnchorView() {
364 return launcher_view_
->tooltip_manager()->anchor_
;
368 launcher_view_
->tooltip_manager()->ShowInternal();
371 LauncherModel
* model_
;
372 internal::LauncherView
* launcher_view_
;
374 scoped_ptr
<LauncherViewTestAPI
> test_api_
;
377 DISALLOW_COPY_AND_ASSIGN(LauncherViewTest
);
380 // Checks that the icon positions do not shift with a state change.
381 TEST_F(LauncherViewTest
, NoStateChangeIconMovement
) {
382 LauncherID last_added
= AddAppShortcut();
383 internal::LauncherButton
* button
= GetButtonByID(last_added
);
384 EXPECT_EQ(button
->state(), ash::internal::LauncherButton::STATE_NORMAL
);
385 gfx::Rect old_bounds
= button
->GetIconBounds();
387 button
->AddState(ash::internal::LauncherButton::STATE_HOVERED
);
388 gfx::Rect hovered_bounds
= button
->GetIconBounds();
389 EXPECT_EQ(old_bounds
.ToString(), hovered_bounds
.ToString());
392 // Adds browser button until overflow and verifies that the last added browser
394 TEST_F(LauncherViewTest
, AddBrowserUntilOverflow
) {
395 // All buttons should be visible.
396 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
397 test_api_
->GetButtonCount());
399 // Add tabbed browser until overflow.
401 LauncherID last_added
= AddTabbedBrowser();
402 while (!test_api_
->IsOverflowButtonVisible()) {
403 // Added button is visible after animation while in this loop.
404 EXPECT_TRUE(GetButtonByID(last_added
)->visible());
406 last_added
= AddTabbedBrowser();
408 ASSERT_LT(items_added
, 10000);
411 // The last added button should be invisible.
412 EXPECT_FALSE(GetButtonByID(last_added
)->visible());
415 // Adds one browser button then adds app shortcut until overflow. Verifies that
416 // the browser button gets hidden on overflow and last added app shortcut is
418 TEST_F(LauncherViewTest
, AddAppShortcutWithBrowserButtonUntilOverflow
) {
419 // All buttons should be visible.
420 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
421 test_api_
->GetButtonCount());
423 LauncherID browser_button_id
= AddTabbedBrowser();
425 // Add app shortcut until overflow.
427 LauncherID last_added
= AddAppShortcut();
428 while (!test_api_
->IsOverflowButtonVisible()) {
429 // Added button is visible after animation while in this loop.
430 EXPECT_TRUE(GetButtonByID(last_added
)->visible());
432 last_added
= AddAppShortcut();
434 ASSERT_LT(items_added
, 10000);
437 // The last added app short button should be visible.
438 EXPECT_TRUE(GetButtonByID(last_added
)->visible());
439 // And the browser button is invisible.
440 EXPECT_FALSE(GetButtonByID(browser_button_id
)->visible());
443 TEST_F(LauncherViewTest
, AddPanelHidesTabbedBrowser
) {
444 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
445 test_api_
->GetButtonCount());
447 // Add tabbed browser until overflow, remember last visible tabbed browser.
449 LauncherID first_added
= AddTabbedBrowser();
450 EXPECT_TRUE(GetButtonByID(first_added
)->visible());
451 LauncherID last_visible
= first_added
;
453 LauncherID added
= AddTabbedBrowser();
454 if (test_api_
->IsOverflowButtonVisible()) {
455 EXPECT_FALSE(GetButtonByID(added
)->visible());
458 last_visible
= added
;
460 ASSERT_LT(items_added
, 10000);
463 LauncherID panel
= AddPanel();
464 EXPECT_TRUE(GetButtonByID(panel
)->visible());
465 EXPECT_FALSE(GetButtonByID(last_visible
)->visible());
468 EXPECT_TRUE(GetButtonByID(last_visible
)->visible());
471 // When there are more panels then browsers we should hide panels rather
473 TEST_F(LauncherViewTest
, BrowserHidesExcessPanels
) {
474 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
475 test_api_
->GetButtonCount());
477 // Add tabbed browser.
478 LauncherID browser
= AddTabbedBrowser();
479 LauncherID first_panel
= AddPanel();
481 EXPECT_TRUE(GetButtonByID(browser
)->visible());
482 EXPECT_TRUE(GetButtonByID(first_panel
)->visible());
484 // Add panels until there is an overflow.
485 LauncherID last_panel
= first_panel
;
487 while (!test_api_
->IsOverflowButtonVisible()) {
488 last_panel
= AddPanel();
490 ASSERT_LT(items_added
, 10000);
493 // The first panel should now be hidden by the new browsers needing space.
494 EXPECT_FALSE(GetButtonByID(first_panel
)->visible());
495 EXPECT_TRUE(GetButtonByID(last_panel
)->visible());
496 EXPECT_TRUE(GetButtonByID(browser
)->visible());
498 // Adding browsers should eventually begin to hide browsers. We will add
499 // browsers until either the last panel or browser is hidden.
501 while (GetButtonByID(browser
)->visible() &&
502 GetButtonByID(last_panel
)->visible()) {
503 browser
= AddTabbedBrowser();
505 ASSERT_LT(items_added
, 10000);
507 EXPECT_TRUE(GetButtonByID(last_panel
)->visible());
508 EXPECT_FALSE(GetButtonByID(browser
)->visible());
511 // Adds button until overflow then removes first added one. Verifies that
512 // the last added one changes from invisible to visible and overflow
514 TEST_F(LauncherViewTest
, RemoveButtonRevealsOverflowed
) {
515 // All buttons should be visible.
516 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
517 test_api_
->GetButtonCount());
519 // Add tabbed browser until overflow.
521 LauncherID first_added
= AddTabbedBrowser();
522 LauncherID last_added
= first_added
;
523 while (!test_api_
->IsOverflowButtonVisible()) {
524 last_added
= AddTabbedBrowser();
526 ASSERT_LT(items_added
, 10000);
529 // Expect add more than 1 button. First added is visible and last is not.
530 EXPECT_NE(first_added
, last_added
);
531 EXPECT_TRUE(GetButtonByID(first_added
)->visible());
532 EXPECT_FALSE(GetButtonByID(last_added
)->visible());
534 // Remove first added.
535 RemoveByID(first_added
);
537 // Last added button becomes visible and overflow chevron is gone.
538 EXPECT_TRUE(GetButtonByID(last_added
)->visible());
539 EXPECT_EQ(1.0f
, GetButtonByID(last_added
)->layer()->opacity());
540 EXPECT_FALSE(test_api_
->IsOverflowButtonVisible());
543 // Verifies that remove last overflowed button should hide overflow chevron.
544 TEST_F(LauncherViewTest
, RemoveLastOverflowed
) {
545 // All buttons should be visible.
546 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
547 test_api_
->GetButtonCount());
549 // Add tabbed browser until overflow.
551 LauncherID last_added
= AddTabbedBrowser();
552 while (!test_api_
->IsOverflowButtonVisible()) {
553 last_added
= AddTabbedBrowser();
555 ASSERT_LT(items_added
, 10000);
558 RemoveByID(last_added
);
559 EXPECT_FALSE(test_api_
->IsOverflowButtonVisible());
562 // Adds browser button without waiting for animation to finish and verifies
563 // that all added buttons are visible.
564 TEST_F(LauncherViewTest
, AddButtonQuickly
) {
565 // All buttons should be visible.
566 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
567 test_api_
->GetButtonCount());
569 // Add a few tabbed browser quickly without wait for animation.
571 while (!test_api_
->IsOverflowButtonVisible()) {
572 AddTabbedBrowserNoWait();
574 ASSERT_LT(added_count
, 10000);
577 // LauncherView should be big enough to hold at least 3 new buttons.
578 ASSERT_GE(added_count
, 3);
580 // Wait for the last animation to finish.
581 test_api_
->RunMessageLoopUntilAnimationsDone();
583 // Verifies non-overflow buttons are visible.
584 for (int i
= 0; i
<= test_api_
->GetLastVisibleIndex(); ++i
) {
585 internal::LauncherButton
* button
= test_api_
->GetButton(i
);
587 EXPECT_TRUE(button
->visible()) << "button index=" << i
;
588 EXPECT_EQ(1.0f
, button
->layer()->opacity()) << "button index=" << i
;
593 // Check that model changes are handled correctly while a launcher icon is being
595 TEST_F(LauncherViewTest
, ModelChangesWhileDragging
) {
596 internal::LauncherButtonHost
* button_host
= launcher_view_
;
598 std::vector
<std::pair
<LauncherID
, views::View
*> > id_map
;
599 SetupForDragTest(&id_map
);
601 // Dragging changes model order.
602 views::View
* dragged_button
= SimulateDrag(
603 internal::LauncherButtonHost::MOUSE
, 0, 2);
604 std::rotate(id_map
.begin() + kExpectedAppIndex
,
605 id_map
.begin() + kExpectedAppIndex
+ 1,
606 id_map
.begin() + kExpectedAppIndex
+ 3);
607 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
609 // Cancelling the drag operation restores previous order.
610 button_host
->PointerReleasedOnButton(dragged_button
,
611 internal::LauncherButtonHost::MOUSE
,
613 std::rotate(id_map
.begin() + kExpectedAppIndex
,
614 id_map
.begin() + kExpectedAppIndex
+ 2,
615 id_map
.begin() + kExpectedAppIndex
+ 3);
616 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
618 // Deleting an item keeps the remaining intact.
619 dragged_button
= SimulateDrag(internal::LauncherButtonHost::MOUSE
, 0, 2);
620 model_
->RemoveItemAt(kExpectedAppIndex
+ 1);
621 id_map
.erase(id_map
.begin() + kExpectedAppIndex
+ 1);
622 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
623 button_host
->PointerReleasedOnButton(dragged_button
,
624 internal::LauncherButtonHost::MOUSE
,
627 // Adding a launcher item cancels the drag and respects the order.
628 dragged_button
= SimulateDrag(internal::LauncherButtonHost::MOUSE
, 0, 2);
629 LauncherID new_id
= AddAppShortcut();
630 id_map
.insert(id_map
.begin() + kExpectedAppIndex
+ 4,
631 std::make_pair(new_id
, GetButtonByID(new_id
)));
632 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
633 button_host
->PointerReleasedOnButton(dragged_button
,
634 internal::LauncherButtonHost::MOUSE
,
637 // Adding a launcher item at the end (i.e. a panel) canels drag and respects
639 dragged_button
= SimulateDrag(internal::LauncherButtonHost::MOUSE
, 0, 2);
641 id_map
.insert(id_map
.begin() + kExpectedAppIndex
+ 6,
642 std::make_pair(new_id
, GetButtonByID(new_id
)));
643 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
644 button_host
->PointerReleasedOnButton(dragged_button
,
645 internal::LauncherButtonHost::MOUSE
,
649 // Check that 2nd drag from the other pointer would be ignored.
650 TEST_F(LauncherViewTest
, SimultaneousDrag
) {
651 internal::LauncherButtonHost
* button_host
= launcher_view_
;
653 std::vector
<std::pair
<LauncherID
, views::View
*> > id_map
;
654 SetupForDragTest(&id_map
);
656 // Start a mouse drag.
657 views::View
* dragged_button_mouse
= SimulateDrag(
658 internal::LauncherButtonHost::MOUSE
, 0, 2);
659 std::rotate(id_map
.begin() + kExpectedAppIndex
,
660 id_map
.begin() + kExpectedAppIndex
+ 1,
661 id_map
.begin() + kExpectedAppIndex
+ 3);
662 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
663 // Attempt a touch drag before the mouse drag finishes.
664 views::View
* dragged_button_touch
= SimulateDrag(
665 internal::LauncherButtonHost::TOUCH
, 3, 1);
667 // Nothing changes since 2nd drag is ignored.
668 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
670 // Finish the mouse drag.
671 button_host
->PointerReleasedOnButton(dragged_button_mouse
,
672 internal::LauncherButtonHost::MOUSE
,
674 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
676 // Now start a touch drag.
677 dragged_button_touch
= SimulateDrag(
678 internal::LauncherButtonHost::TOUCH
, 3, 1);
679 std::rotate(id_map
.begin() + kExpectedAppIndex
+ 2,
680 id_map
.begin() + kExpectedAppIndex
+ 3,
681 id_map
.begin() + kExpectedAppIndex
+ 4);
682 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
684 // And attempt a mouse drag before the touch drag finishes.
685 dragged_button_mouse
= SimulateDrag(
686 internal::LauncherButtonHost::MOUSE
, 0, 1);
688 // Nothing changes since 2nd drag is ignored.
689 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
691 button_host
->PointerReleasedOnButton(dragged_button_touch
,
692 internal::LauncherButtonHost::TOUCH
,
694 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map
));
697 // Confirm that item status changes are reflected in the buttons.
698 TEST_F(LauncherViewTest
, LauncherItemStatus
) {
699 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
700 test_api_
->GetButtonCount());
702 // Add tabbed browser.
703 LauncherID last_added
= AddTabbedBrowser();
704 LauncherItem item
= GetItemByID(last_added
);
705 int index
= model_
->ItemIndexByID(last_added
);
706 internal::LauncherButton
* button
= GetButtonByID(last_added
);
707 ASSERT_EQ(internal::LauncherButton::STATE_RUNNING
, button
->state());
708 item
.status
= ash::STATUS_ACTIVE
;
709 model_
->Set(index
, item
);
710 ASSERT_EQ(internal::LauncherButton::STATE_ACTIVE
, button
->state());
711 item
.status
= ash::STATUS_ATTENTION
;
712 model_
->Set(index
, item
);
713 ASSERT_EQ(internal::LauncherButton::STATE_ATTENTION
, button
->state());
716 // Confirm that item status changes are reflected in the buttons
717 // for platform apps.
718 TEST_F(LauncherViewTest
, LauncherItemStatusPlatformApp
) {
719 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
720 test_api_
->GetButtonCount());
722 // Add tabbed browser.
723 LauncherID last_added
= AddPlatformApp();
724 LauncherItem item
= GetItemByID(last_added
);
725 int index
= model_
->ItemIndexByID(last_added
);
726 internal::LauncherButton
* button
= GetButtonByID(last_added
);
727 ASSERT_EQ(internal::LauncherButton::STATE_RUNNING
, button
->state());
728 item
.status
= ash::STATUS_ACTIVE
;
729 model_
->Set(index
, item
);
730 ASSERT_EQ(internal::LauncherButton::STATE_ACTIVE
, button
->state());
731 item
.status
= ash::STATUS_ATTENTION
;
732 model_
->Set(index
, item
);
733 ASSERT_EQ(internal::LauncherButton::STATE_ATTENTION
, button
->state());
736 // Confirm that launcher item bounds are correctly updated on shelf changes.
737 TEST_F(LauncherViewTest
, LauncherItemBoundsCheck
) {
738 internal::ShelfLayoutManager
* shelf_layout_manager
=
739 Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
740 VerifyLauncherItemBoundsAreValid();
741 shelf_layout_manager
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
742 test_api_
->RunMessageLoopUntilAnimationsDone();
743 VerifyLauncherItemBoundsAreValid();
744 shelf_layout_manager
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER
);
745 test_api_
->RunMessageLoopUntilAnimationsDone();
746 VerifyLauncherItemBoundsAreValid();
749 TEST_F(LauncherViewTest
, LauncherTooltipTest
) {
750 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
751 test_api_
->GetButtonCount());
753 // Prepare some items to the launcher.
754 LauncherID app_button_id
= AddAppShortcut();
755 LauncherID tab_button_id
= AddTabbedBrowser();
757 internal::LauncherButton
* app_button
= GetButtonByID(app_button_id
);
758 internal::LauncherButton
* tab_button
= GetButtonByID(tab_button_id
);
760 internal::LauncherButtonHost
* button_host
= launcher_view_
;
761 internal::LauncherTooltipManager
* tooltip_manager
=
762 launcher_view_
->tooltip_manager();
764 button_host
->MouseEnteredButton(app_button
);
765 // There's a delay to show the tooltip, so it's not visible yet.
766 EXPECT_FALSE(tooltip_manager
->IsVisible());
767 EXPECT_EQ(app_button
, GetTooltipAnchorView());
770 EXPECT_TRUE(tooltip_manager
->IsVisible());
772 // Once it's visible, it keeps visibility and is pointing to the same
774 button_host
->MouseExitedButton(app_button
);
775 EXPECT_TRUE(tooltip_manager
->IsVisible());
776 EXPECT_EQ(app_button
, GetTooltipAnchorView());
778 // When entered to another item, it switches to the new item. There is no
779 // delay for the visibility.
780 button_host
->MouseEnteredButton(tab_button
);
781 EXPECT_TRUE(tooltip_manager
->IsVisible());
782 EXPECT_EQ(tab_button
, GetTooltipAnchorView());
784 button_host
->MouseExitedButton(tab_button
);
785 tooltip_manager
->Close();
787 // Next time: enter app_button -> move immediately to tab_button.
788 button_host
->MouseEnteredButton(app_button
);
789 button_host
->MouseExitedButton(app_button
);
790 button_host
->MouseEnteredButton(tab_button
);
791 EXPECT_FALSE(tooltip_manager
->IsVisible());
792 EXPECT_EQ(tab_button
, GetTooltipAnchorView());
795 TEST_F(LauncherViewTest
, ShouldHideTooltipTest
) {
796 LauncherID app_button_id
= AddAppShortcut();
797 LauncherID tab_button_id
= AddTabbedBrowser();
799 // The tooltip shouldn't hide if the mouse is on normal buttons.
800 for (int i
= 0; i
< test_api_
->GetButtonCount(); i
++) {
801 internal::LauncherButton
* button
= test_api_
->GetButton(i
);
805 EXPECT_FALSE(launcher_view_
->ShouldHideTooltip(
806 button
->GetMirroredBounds().CenterPoint()))
807 << "LauncherView tries to hide on button " << i
;
810 // The tooltip should not hide on the app-list button.
811 views::View
* app_list_button
= launcher_view_
->GetAppListButtonView();
812 EXPECT_FALSE(launcher_view_
->ShouldHideTooltip(
813 app_list_button
->GetMirroredBounds().CenterPoint()));
815 // The tooltip shouldn't hide if the mouse is in the gap between two buttons.
816 gfx::Rect app_button_rect
= GetButtonByID(app_button_id
)->GetMirroredBounds();
817 gfx::Rect tab_button_rect
= GetButtonByID(tab_button_id
)->GetMirroredBounds();
818 ASSERT_FALSE(app_button_rect
.Intersects(tab_button_rect
));
819 EXPECT_FALSE(launcher_view_
->ShouldHideTooltip(
820 gfx::UnionRects(app_button_rect
, tab_button_rect
).CenterPoint()));
822 // The tooltip should hide if it's outside of all buttons.
824 for (int i
= 0; i
< test_api_
->GetButtonCount(); i
++) {
825 internal::LauncherButton
* button
= test_api_
->GetButton(i
);
829 all_area
.Union(button
->GetMirroredBounds());
831 all_area
.Union(launcher_view_
->GetAppListButtonView()->GetMirroredBounds());
832 EXPECT_FALSE(launcher_view_
->ShouldHideTooltip(all_area
.origin()));
833 EXPECT_FALSE(launcher_view_
->ShouldHideTooltip(
834 gfx::Point(all_area
.right() - 1, all_area
.bottom() - 1)));
835 EXPECT_TRUE(launcher_view_
->ShouldHideTooltip(
836 gfx::Point(all_area
.right(), all_area
.y())));
837 EXPECT_TRUE(launcher_view_
->ShouldHideTooltip(
838 gfx::Point(all_area
.x() - 1, all_area
.y())));
839 EXPECT_TRUE(launcher_view_
->ShouldHideTooltip(
840 gfx::Point(all_area
.x(), all_area
.y() - 1)));
841 EXPECT_TRUE(launcher_view_
->ShouldHideTooltip(
842 gfx::Point(all_area
.x(), all_area
.bottom())));
845 TEST_F(LauncherViewTest
, ShouldHideTooltipWithAppListWindowTest
) {
846 Shell::GetInstance()->ToggleAppList(NULL
);
847 ASSERT_TRUE(Shell::GetInstance()->GetAppListWindow());
849 // The tooltip shouldn't hide if the mouse is on normal buttons.
850 for (int i
= 1; i
< test_api_
->GetButtonCount(); i
++) {
851 internal::LauncherButton
* button
= test_api_
->GetButton(i
);
855 EXPECT_FALSE(launcher_view_
->ShouldHideTooltip(
856 button
->GetMirroredBounds().CenterPoint()))
857 << "LauncherView tries to hide on button " << i
;
860 // The tooltip should hide on the app-list button.
861 views::View
* app_list_button
= launcher_view_
->GetAppListButtonView();
862 EXPECT_TRUE(launcher_view_
->ShouldHideTooltip(
863 app_list_button
->GetMirroredBounds().CenterPoint()));
866 // Resizing launcher view while an add animation without fade-in is running,
867 // which happens when overflow happens. App list button should end up in its
869 TEST_F(LauncherViewTest
, ResizeDuringOverflowAddAnimation
) {
870 // All buttons should be visible.
871 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
872 test_api_
->GetButtonCount());
874 // Add buttons until overflow. Let the non-overflow add animations finish but
875 // leave the last running.
877 AddTabbedBrowserNoWait();
878 while (!test_api_
->IsOverflowButtonVisible()) {
879 test_api_
->RunMessageLoopUntilAnimationsDone();
880 AddTabbedBrowserNoWait();
882 ASSERT_LT(items_added
, 10000);
885 // Resize launcher view with that animation running and stay overflown.
886 gfx::Rect bounds
= launcher_view_
->bounds();
887 bounds
.set_width(bounds
.width() - kLauncherPreferredSize
);
888 launcher_view_
->SetBoundsRect(bounds
);
889 ASSERT_TRUE(test_api_
->IsOverflowButtonVisible());
891 // Finish the animation.
892 test_api_
->RunMessageLoopUntilAnimationsDone();
894 // App list button should ends up in its new ideal bounds.
895 const int app_list_button_index
= test_api_
->GetButtonCount() - 1;
896 const gfx::Rect
& app_list_ideal_bounds
=
897 test_api_
->GetIdealBoundsByIndex(app_list_button_index
);
898 const gfx::Rect
& app_list_bounds
=
899 test_api_
->GetBoundsByIndex(app_list_button_index
);
900 EXPECT_EQ(app_list_bounds
, app_list_ideal_bounds
);
903 // Check that the first item in the list follows Fitt's law by including the
904 // first pixel and being therefore bigger then the others.
905 TEST_F(LauncherViewTest
, CheckFittsLaw
) {
906 // All buttons should be visible.
907 ASSERT_EQ(test_api_
->GetLastVisibleIndex() + 1,
908 test_api_
->GetButtonCount());
909 gfx::Rect ideal_bounds_0
= test_api_
->GetIdealBoundsByIndex(0);
910 gfx::Rect ideal_bounds_1
= test_api_
->GetIdealBoundsByIndex(1);
911 EXPECT_GT(ideal_bounds_0
.width(), ideal_bounds_1
.width());