Search engine setting: Make "Make default" not mouse-focusable.
[chromium-blink-merge.git] / ash / launcher / launcher_view_unittest.cc
blob662284fab6f2c82ac58da2525ba8fd3b7bfb280a
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"
7 #include <algorithm>
8 #include <vector>
10 #include "ash/ash_switches.h"
11 #include "ash/launcher/launcher.h"
12 #include "ash/launcher/launcher_button.h"
13 #include "ash/launcher/launcher_icon_observer.h"
14 #include "ash/launcher/launcher_model.h"
15 #include "ash/launcher/launcher_tooltip_manager.h"
16 #include "ash/root_window_controller.h"
17 #include "ash/shelf/shelf_layout_manager.h"
18 #include "ash/shelf/shelf_widget.h"
19 #include "ash/shell.h"
20 #include "ash/shell_window_ids.h"
21 #include "ash/test/ash_test_base.h"
22 #include "ash/test/launcher_view_test_api.h"
23 #include "ash/test/shell_test_api.h"
24 #include "ash/test/test_launcher_delegate.h"
25 #include "base/basictypes.h"
26 #include "base/command_line.h"
27 #include "base/compiler_specific.h"
28 #include "base/memory/scoped_ptr.h"
29 #include "grit/ash_resources.h"
30 #include "ui/aura/root_window.h"
31 #include "ui/aura/test/aura_test_base.h"
32 #include "ui/aura/test/event_generator.h"
33 #include "ui/aura/window.h"
34 #include "ui/base/events/event.h"
35 #include "ui/base/events/event_constants.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/compositor/layer.h"
38 #include "ui/views/view_model.h"
39 #include "ui/views/widget/widget.h"
40 #include "ui/views/widget/widget_delegate.h"
42 namespace ash {
43 namespace test {
45 ////////////////////////////////////////////////////////////////////////////////
46 // LauncherIconObserver tests.
48 class TestLauncherIconObserver : public LauncherIconObserver {
49 public:
50 explicit TestLauncherIconObserver(Launcher* launcher)
51 : launcher_(launcher),
52 change_notified_(false) {
53 if (launcher_)
54 launcher_->AddIconObserver(this);
57 virtual ~TestLauncherIconObserver() {
58 if (launcher_)
59 launcher_->RemoveIconObserver(this);
62 // LauncherIconObserver implementation.
63 virtual void OnLauncherIconPositionsChanged() OVERRIDE {
64 change_notified_ = true;
67 int change_notified() const { return change_notified_; }
68 void Reset() { change_notified_ = false; }
70 private:
71 Launcher* launcher_;
72 bool change_notified_;
74 DISALLOW_COPY_AND_ASSIGN(TestLauncherIconObserver);
77 class LauncherViewIconObserverTest : public ash::test::AshTestBase {
78 public:
79 LauncherViewIconObserverTest() {}
80 virtual ~LauncherViewIconObserverTest() {}
82 virtual void SetUp() OVERRIDE {
83 AshTestBase::SetUp();
84 Launcher* launcher = Launcher::ForPrimaryDisplay();
85 observer_.reset(new TestLauncherIconObserver(launcher));
87 launcher_view_test_.reset(new LauncherViewTestAPI(
88 launcher->GetLauncherViewForTest()));
89 launcher_view_test_->SetAnimationDuration(1);
92 virtual void TearDown() OVERRIDE {
93 observer_.reset();
94 AshTestBase::TearDown();
97 TestLauncherIconObserver* observer() { return observer_.get(); }
99 LauncherViewTestAPI* launcher_view_test() {
100 return launcher_view_test_.get();
103 Launcher* LauncherForSecondaryDisplay() {
104 return Launcher::ForWindow(Shell::GetAllRootWindows()[1]);
107 private:
108 scoped_ptr<TestLauncherIconObserver> observer_;
109 scoped_ptr<LauncherViewTestAPI> launcher_view_test_;
111 DISALLOW_COPY_AND_ASSIGN(LauncherViewIconObserverTest);
114 TEST_F(LauncherViewIconObserverTest, AddRemove) {
115 ash::test::TestLauncherDelegate* launcher_delegate =
116 ash::test::TestLauncherDelegate::instance();
117 ASSERT_TRUE(launcher_delegate);
119 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
120 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
121 params.bounds = gfx::Rect(0, 0, 200, 200);
122 params.context = CurrentContext();
124 scoped_ptr<views::Widget> widget(new views::Widget());
125 widget->Init(params);
126 launcher_delegate->AddLauncherItem(widget->GetNativeWindow());
127 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
128 EXPECT_TRUE(observer()->change_notified());
129 observer()->Reset();
131 widget->Show();
132 widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
133 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
134 EXPECT_TRUE(observer()->change_notified());
135 observer()->Reset();
138 // Sometimes fails on trybots on win7_aura. http://crbug.com/177135
139 #if defined(OS_WIN)
140 #define MAYBE_AddRemoveWithMultipleDisplays \
141 DISABLED_AddRemoveWithMultipleDisplays
142 #else
143 #define MAYBE_AddRemoveWithMultipleDisplays \
144 AddRemoveWithMultipleDisplays
145 #endif
146 // Make sure creating/deleting an window on one displays notifies a
147 // launcher on external display as well as one on primary.
148 TEST_F(LauncherViewIconObserverTest, MAYBE_AddRemoveWithMultipleDisplays) {
149 UpdateDisplay("400x400,400x400");
150 TestLauncherIconObserver second_observer(LauncherForSecondaryDisplay());
152 ash::test::TestLauncherDelegate* launcher_delegate =
153 ash::test::TestLauncherDelegate::instance();
154 ASSERT_TRUE(launcher_delegate);
156 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
157 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
158 params.bounds = gfx::Rect(0, 0, 200, 200);
159 params.context = CurrentContext();
161 scoped_ptr<views::Widget> widget(new views::Widget());
162 widget->Init(params);
163 launcher_delegate->AddLauncherItem(widget->GetNativeWindow());
164 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
165 EXPECT_TRUE(observer()->change_notified());
166 EXPECT_TRUE(second_observer.change_notified());
167 observer()->Reset();
168 second_observer.Reset();
170 widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
171 launcher_view_test()->RunMessageLoopUntilAnimationsDone();
172 EXPECT_TRUE(observer()->change_notified());
173 EXPECT_TRUE(second_observer.change_notified());
175 observer()->Reset();
176 second_observer.Reset();
179 TEST_F(LauncherViewIconObserverTest, BoundsChanged) {
180 ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
181 Launcher* launcher = Launcher::ForPrimaryDisplay();
182 gfx::Size shelf_size =
183 shelf->GetWindowBoundsInScreen().size();
184 shelf_size.set_width(shelf_size.width() / 2);
185 ASSERT_GT(shelf_size.width(), 0);
186 launcher->SetLauncherViewBounds(gfx::Rect(shelf_size));
187 // No animation happens for LauncherView bounds change.
188 EXPECT_TRUE(observer()->change_notified());
189 observer()->Reset();
192 ////////////////////////////////////////////////////////////////////////////////
193 // LauncherView tests.
195 class LauncherViewTest : public AshTestBase {
196 public:
197 LauncherViewTest() : model_(NULL), launcher_view_(NULL) {}
198 virtual ~LauncherViewTest() {}
200 virtual void SetUp() OVERRIDE {
201 AshTestBase::SetUp();
202 test::ShellTestApi test_api(Shell::GetInstance());
203 model_ = test_api.launcher_model();
204 Launcher* launcher = Launcher::ForPrimaryDisplay();
205 launcher_view_ = launcher->GetLauncherViewForTest();
207 // The bounds should be big enough for 4 buttons + overflow chevron.
208 launcher_view_->SetBounds(0, 0, 500, 50);
210 test_api_.reset(new LauncherViewTestAPI(launcher_view_));
211 test_api_->SetAnimationDuration(1); // Speeds up animation for test.
213 // Add browser shortcut launcher item at index 0 for test.
214 AddBrowserShortcut();
217 virtual void TearDown() OVERRIDE {
218 test_api_.reset();
219 AshTestBase::TearDown();
222 protected:
223 LauncherID AddBrowserShortcut() {
224 LauncherItem browser_shortcut;
225 browser_shortcut.type = TYPE_BROWSER_SHORTCUT;
226 browser_shortcut.is_incognito = false;
228 LauncherID id = model_->next_id();
229 model_->AddAt(0, browser_shortcut);
230 test_api_->RunMessageLoopUntilAnimationsDone();
231 return id;
234 LauncherID AddAppShortcut() {
235 LauncherItem item;
236 item.type = TYPE_APP_SHORTCUT;
237 item.status = STATUS_CLOSED;
239 LauncherID id = model_->next_id();
240 model_->Add(item);
241 test_api_->RunMessageLoopUntilAnimationsDone();
242 return id;
245 LauncherID AddTabbedBrowserNoWait() {
246 LauncherItem item;
247 item.type = TYPE_TABBED;
248 item.status = STATUS_RUNNING;
250 LauncherID id = model_->next_id();
251 model_->Add(item);
252 return id;
255 LauncherID AddTabbedBrowser() {
256 LauncherID id = AddTabbedBrowserNoWait();
257 test_api_->RunMessageLoopUntilAnimationsDone();
258 return id;
261 LauncherID AddPanel() {
262 LauncherID id = AddPanelNoWait();
263 test_api_->RunMessageLoopUntilAnimationsDone();
264 return id;
267 LauncherID AddPlatformAppNoWait() {
268 LauncherItem item;
269 item.type = TYPE_PLATFORM_APP;
270 item.status = STATUS_RUNNING;
272 LauncherID id = model_->next_id();
273 model_->Add(item);
274 return id;
277 LauncherID AddPanelNoWait() {
278 LauncherItem item;
279 item.type = TYPE_APP_PANEL;
280 item.status = STATUS_RUNNING;
282 LauncherID id = model_->next_id();
283 model_->Add(item);
284 return id;
287 LauncherID AddPlatformApp() {
288 LauncherID id = AddPlatformAppNoWait();
289 test_api_->RunMessageLoopUntilAnimationsDone();
290 return id;
293 void RemoveByID(LauncherID id) {
294 model_->RemoveItemAt(model_->ItemIndexByID(id));
295 test_api_->RunMessageLoopUntilAnimationsDone();
298 internal::LauncherButton* GetButtonByID(LauncherID id) {
299 int index = model_->ItemIndexByID(id);
300 return test_api_->GetButton(index);
303 LauncherItem GetItemByID(LauncherID id) {
304 LauncherItems::const_iterator items = model_->ItemByID(id);
305 return *items;
308 void CheckModelIDs(
309 const std::vector<std::pair<LauncherID, views::View*> >& id_map) {
310 size_t map_index = 0;
311 for (size_t model_index = 0;
312 model_index < model_->items().size();
313 ++model_index) {
314 ash::LauncherItem item = model_->items()[model_index];
315 ash::LauncherID id = item.id;
316 EXPECT_EQ(id_map[map_index].first, id);
317 EXPECT_EQ(id_map[map_index].second, GetButtonByID(id));
318 ++map_index;
320 ASSERT_EQ(map_index, id_map.size());
323 void VerifyLauncherItemBoundsAreValid() {
324 for (int i=0;i <= test_api_->GetLastVisibleIndex(); ++i) {
325 if (test_api_->GetButton(i)) {
326 gfx::Rect launcher_view_bounds = launcher_view_->GetLocalBounds();
327 gfx::Rect item_bounds = test_api_->GetBoundsByIndex(i);
328 EXPECT_TRUE(item_bounds.x() >= 0);
329 EXPECT_TRUE(item_bounds.y() >= 0);
330 EXPECT_TRUE(item_bounds.right() <= launcher_view_bounds.width());
331 EXPECT_TRUE(item_bounds.bottom() <= launcher_view_bounds.height());
336 views::View* SimulateDrag(internal::LauncherButtonHost::Pointer pointer,
337 int button_index,
338 int destination_index) {
339 internal::LauncherButtonHost* button_host = launcher_view_;
341 // Mouse down.
342 views::View* button = test_api_->GetButton(button_index);
343 ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED,
344 button->bounds().origin(),
345 button->bounds().origin(), 0);
346 button_host->PointerPressedOnButton(button, pointer, click_event);
348 // Drag.
349 views::View* destination = test_api_->GetButton(destination_index);
350 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
351 destination->bounds().origin(),
352 destination->bounds().origin(), 0);
353 button_host->PointerDraggedOnButton(button, pointer, drag_event);
354 return button;
357 void SetupForDragTest(
358 std::vector<std::pair<LauncherID, views::View*> >* id_map) {
359 // Initialize |id_map| with the automatically-created launcher buttons.
360 for (size_t i = 0; i < model_->items().size(); ++i) {
361 internal::LauncherButton* button = test_api_->GetButton(i);
362 id_map->push_back(std::make_pair(model_->items()[i].id, button));
364 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
366 // Add 5 app launcher buttons for testing.
367 for (int i = 0; i < 5; ++i) {
368 LauncherID id = AddAppShortcut();
369 // browser shortcut is located at index 0. So we should start to add app
370 // shortcut at index 1.
371 id_map->insert(id_map->begin() + (i + 1),
372 std::make_pair(id, GetButtonByID(id)));
374 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
377 views::View* GetTooltipAnchorView() {
378 return launcher_view_->tooltip_manager()->anchor_;
381 void ShowTooltip() {
382 launcher_view_->tooltip_manager()->ShowInternal();
385 LauncherModel* model_;
386 internal::LauncherView* launcher_view_;
388 scoped_ptr<LauncherViewTestAPI> test_api_;
390 private:
391 DISALLOW_COPY_AND_ASSIGN(LauncherViewTest);
394 class LauncherViewTextDirectionTest
395 : public LauncherViewTest,
396 public testing::WithParamInterface<bool> {
397 public:
398 LauncherViewTextDirectionTest() : is_rtl_(GetParam()) {}
399 virtual ~LauncherViewTextDirectionTest() {}
401 virtual void SetUp() OVERRIDE {
402 LauncherViewTest::SetUp();
403 original_locale_ = l10n_util::GetApplicationLocale(std::string());
404 if (is_rtl_)
405 base::i18n::SetICUDefaultLocale("he");
406 ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
409 virtual void TearDown() OVERRIDE {
410 if (is_rtl_)
411 base::i18n::SetICUDefaultLocale(original_locale_);
412 LauncherViewTest::TearDown();
415 private:
416 bool is_rtl_;
417 std::string original_locale_;
419 DISALLOW_COPY_AND_ASSIGN(LauncherViewTextDirectionTest);
422 // Checks that the ideal item icon bounds match the view's bounds in the screen
423 // in both LTR and RTL.
424 TEST_P(LauncherViewTextDirectionTest, IdealBoundsOfItemIcon) {
425 LauncherID id = AddTabbedBrowser();
426 internal::LauncherButton* button = GetButtonByID(id);
427 gfx::Rect item_bounds = button->GetBoundsInScreen();
428 gfx::Point icon_offset = button->GetIconBounds().origin();
429 item_bounds.Offset(icon_offset.OffsetFromOrigin());
430 gfx::Rect ideal_bounds = launcher_view_->GetIdealBoundsOfItemIcon(id);
431 gfx::Point screen_origin;
432 views::View::ConvertPointToScreen(launcher_view_, &screen_origin);
433 ideal_bounds.Offset(screen_origin.x(), screen_origin.y());
434 EXPECT_EQ(item_bounds.x(), ideal_bounds.x());
435 EXPECT_EQ(item_bounds.y(), ideal_bounds.y());
438 // Adds browser button until overflow and verifies that the last added browser
439 // button is hidden.
440 TEST_F(LauncherViewTest, AddBrowserUntilOverflow) {
441 // All buttons should be visible.
442 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
443 test_api_->GetButtonCount());
445 // Add tabbed browser until overflow.
446 int items_added = 0;
447 LauncherID last_added = AddTabbedBrowser();
448 while (!test_api_->IsOverflowButtonVisible()) {
449 // Added button is visible after animation while in this loop.
450 EXPECT_TRUE(GetButtonByID(last_added)->visible());
452 last_added = AddTabbedBrowser();
453 ++items_added;
454 ASSERT_LT(items_added, 10000);
457 // The last added button should be invisible.
458 EXPECT_FALSE(GetButtonByID(last_added)->visible());
461 // Adds one browser button then adds app shortcut until overflow. Verifies that
462 // the browser button gets hidden on overflow and last added app shortcut is
463 // still visible.
464 TEST_F(LauncherViewTest, AddAppShortcutWithBrowserButtonUntilOverflow) {
465 // All buttons should be visible.
466 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
467 test_api_->GetButtonCount());
469 LauncherID browser_button_id = AddTabbedBrowser();
471 // Add app shortcut until overflow.
472 int items_added = 0;
473 LauncherID last_added = AddAppShortcut();
474 while (!test_api_->IsOverflowButtonVisible()) {
475 // Added button is visible after animation while in this loop.
476 EXPECT_TRUE(GetButtonByID(last_added)->visible());
478 last_added = AddAppShortcut();
479 ++items_added;
480 ASSERT_LT(items_added, 10000);
483 // The last added app short button should be visible.
484 EXPECT_TRUE(GetButtonByID(last_added)->visible());
485 // And the browser button is invisible.
486 EXPECT_FALSE(GetButtonByID(browser_button_id)->visible());
489 TEST_F(LauncherViewTest, AddPanelHidesTabbedBrowser) {
490 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
491 test_api_->GetButtonCount());
493 // Add tabbed browser until overflow, remember last visible tabbed browser.
494 int items_added = 0;
495 LauncherID first_added = AddTabbedBrowser();
496 EXPECT_TRUE(GetButtonByID(first_added)->visible());
497 LauncherID last_visible = first_added;
498 while (true) {
499 LauncherID added = AddTabbedBrowser();
500 if (test_api_->IsOverflowButtonVisible()) {
501 EXPECT_FALSE(GetButtonByID(added)->visible());
502 break;
504 last_visible = added;
505 ++items_added;
506 ASSERT_LT(items_added, 10000);
509 LauncherID panel = AddPanel();
510 EXPECT_TRUE(GetButtonByID(panel)->visible());
511 EXPECT_FALSE(GetButtonByID(last_visible)->visible());
513 RemoveByID(panel);
514 EXPECT_TRUE(GetButtonByID(last_visible)->visible());
517 // When there are more panels then browsers we should hide panels rather
518 // than browsers.
519 TEST_F(LauncherViewTest, BrowserHidesExcessPanels) {
520 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
521 test_api_->GetButtonCount());
523 // Add tabbed browser.
524 LauncherID browser = AddTabbedBrowser();
525 LauncherID first_panel = AddPanel();
527 EXPECT_TRUE(GetButtonByID(browser)->visible());
528 EXPECT_TRUE(GetButtonByID(first_panel)->visible());
530 // Add panels until there is an overflow.
531 LauncherID last_panel = first_panel;
532 int items_added = 0;
533 while (!test_api_->IsOverflowButtonVisible()) {
534 last_panel = AddPanel();
535 ++items_added;
536 ASSERT_LT(items_added, 10000);
539 // The first panel should now be hidden by the new browsers needing space.
540 EXPECT_FALSE(GetButtonByID(first_panel)->visible());
541 EXPECT_TRUE(GetButtonByID(last_panel)->visible());
542 EXPECT_TRUE(GetButtonByID(browser)->visible());
544 // Adding browsers should eventually begin to hide browsers. We will add
545 // browsers until either the last panel or browser is hidden.
546 items_added = 0;
547 while (GetButtonByID(browser)->visible() &&
548 GetButtonByID(last_panel)->visible()) {
549 browser = AddTabbedBrowser();
550 ++items_added;
551 ASSERT_LT(items_added, 10000);
553 EXPECT_TRUE(GetButtonByID(last_panel)->visible());
554 EXPECT_FALSE(GetButtonByID(browser)->visible());
557 // Adds button until overflow then removes first added one. Verifies that
558 // the last added one changes from invisible to visible and overflow
559 // chevron is gone.
560 TEST_F(LauncherViewTest, RemoveButtonRevealsOverflowed) {
561 // All buttons should be visible.
562 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
563 test_api_->GetButtonCount());
565 // Add tabbed browser until overflow.
566 int items_added = 0;
567 LauncherID first_added = AddTabbedBrowser();
568 LauncherID last_added = first_added;
569 while (!test_api_->IsOverflowButtonVisible()) {
570 last_added = AddTabbedBrowser();
571 ++items_added;
572 ASSERT_LT(items_added, 10000);
575 // Expect add more than 1 button. First added is visible and last is not.
576 EXPECT_NE(first_added, last_added);
577 EXPECT_TRUE(GetButtonByID(first_added)->visible());
578 EXPECT_FALSE(GetButtonByID(last_added)->visible());
580 // Remove first added.
581 RemoveByID(first_added);
583 // Last added button becomes visible and overflow chevron is gone.
584 EXPECT_TRUE(GetButtonByID(last_added)->visible());
585 EXPECT_EQ(1.0f, GetButtonByID(last_added)->layer()->opacity());
586 EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
589 // Verifies that remove last overflowed button should hide overflow chevron.
590 TEST_F(LauncherViewTest, RemoveLastOverflowed) {
591 // All buttons should be visible.
592 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
593 test_api_->GetButtonCount());
595 // Add tabbed browser until overflow.
596 int items_added = 0;
597 LauncherID last_added = AddTabbedBrowser();
598 while (!test_api_->IsOverflowButtonVisible()) {
599 last_added = AddTabbedBrowser();
600 ++items_added;
601 ASSERT_LT(items_added, 10000);
604 RemoveByID(last_added);
605 EXPECT_FALSE(test_api_->IsOverflowButtonVisible());
608 // Adds browser button without waiting for animation to finish and verifies
609 // that all added buttons are visible.
610 TEST_F(LauncherViewTest, AddButtonQuickly) {
611 // All buttons should be visible.
612 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
613 test_api_->GetButtonCount());
615 // Add a few tabbed browser quickly without wait for animation.
616 int added_count = 0;
617 while (!test_api_->IsOverflowButtonVisible()) {
618 AddTabbedBrowserNoWait();
619 ++added_count;
620 ASSERT_LT(added_count, 10000);
623 // LauncherView should be big enough to hold at least 3 new buttons.
624 ASSERT_GE(added_count, 3);
626 // Wait for the last animation to finish.
627 test_api_->RunMessageLoopUntilAnimationsDone();
629 // Verifies non-overflow buttons are visible.
630 for (int i = 0; i <= test_api_->GetLastVisibleIndex(); ++i) {
631 internal::LauncherButton* button = test_api_->GetButton(i);
632 if (button) {
633 EXPECT_TRUE(button->visible()) << "button index=" << i;
634 EXPECT_EQ(1.0f, button->layer()->opacity()) << "button index=" << i;
639 // Check that model changes are handled correctly while a launcher icon is being
640 // dragged.
641 TEST_F(LauncherViewTest, ModelChangesWhileDragging) {
642 internal::LauncherButtonHost* button_host = launcher_view_;
644 std::vector<std::pair<LauncherID, views::View*> > id_map;
645 SetupForDragTest(&id_map);
647 // Dragging browser shortcut at index 0.
648 EXPECT_TRUE(model_->items()[0].type == TYPE_BROWSER_SHORTCUT);
649 views::View* dragged_button = SimulateDrag(
650 internal::LauncherButtonHost::MOUSE, 0, 2);
651 std::rotate(id_map.begin(),
652 id_map.begin() + 1,
653 id_map.begin() + 3);
654 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
655 button_host->PointerReleasedOnButton(dragged_button,
656 internal::LauncherButtonHost::MOUSE,
657 false);
658 EXPECT_TRUE(model_->items()[2].type == TYPE_BROWSER_SHORTCUT);
660 // Dragging changes model order.
661 dragged_button = SimulateDrag(
662 internal::LauncherButtonHost::MOUSE, 0, 2);
663 std::rotate(id_map.begin(),
664 id_map.begin() + 1,
665 id_map.begin() + 3);
666 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
668 // Cancelling the drag operation restores previous order.
669 button_host->PointerReleasedOnButton(dragged_button,
670 internal::LauncherButtonHost::MOUSE,
671 true);
672 std::rotate(id_map.begin(),
673 id_map.begin() + 2,
674 id_map.begin() + 3);
675 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
677 // Deleting an item keeps the remaining intact.
678 dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
679 model_->RemoveItemAt(1);
680 id_map.erase(id_map.begin() + 1);
681 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
682 button_host->PointerReleasedOnButton(dragged_button,
683 internal::LauncherButtonHost::MOUSE,
684 false);
686 // Adding a launcher item cancels the drag and respects the order.
687 dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
688 LauncherID new_id = AddAppShortcut();
689 id_map.insert(id_map.begin() + 5,
690 std::make_pair(new_id, GetButtonByID(new_id)));
691 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
692 button_host->PointerReleasedOnButton(dragged_button,
693 internal::LauncherButtonHost::MOUSE,
694 false);
696 // Adding a launcher item at the end (i.e. a panel) canels drag and respects
697 // the order.
698 dragged_button = SimulateDrag(internal::LauncherButtonHost::MOUSE, 0, 2);
699 new_id = AddPanel();
700 id_map.insert(id_map.begin() + 7,
701 std::make_pair(new_id, GetButtonByID(new_id)));
702 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
703 button_host->PointerReleasedOnButton(dragged_button,
704 internal::LauncherButtonHost::MOUSE,
705 false);
708 // Check that 2nd drag from the other pointer would be ignored.
709 TEST_F(LauncherViewTest, SimultaneousDrag) {
710 internal::LauncherButtonHost* button_host = launcher_view_;
712 std::vector<std::pair<LauncherID, views::View*> > id_map;
713 SetupForDragTest(&id_map);
715 // Start a mouse drag.
716 views::View* dragged_button_mouse = SimulateDrag(
717 internal::LauncherButtonHost::MOUSE, 0, 2);
718 std::rotate(id_map.begin(),
719 id_map.begin() + 1,
720 id_map.begin() + 3);
721 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
722 // Attempt a touch drag before the mouse drag finishes.
723 views::View* dragged_button_touch = SimulateDrag(
724 internal::LauncherButtonHost::TOUCH, 3, 1);
726 // Nothing changes since 2nd drag is ignored.
727 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
729 // Finish the mouse drag.
730 button_host->PointerReleasedOnButton(dragged_button_mouse,
731 internal::LauncherButtonHost::MOUSE,
732 false);
733 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
735 // Now start a touch drag.
736 dragged_button_touch = SimulateDrag(
737 internal::LauncherButtonHost::TOUCH, 3, 1);
738 std::rotate(id_map.begin() + 2,
739 id_map.begin() + 3,
740 id_map.begin() + 4);
741 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
743 // And attempt a mouse drag before the touch drag finishes.
744 dragged_button_mouse = SimulateDrag(
745 internal::LauncherButtonHost::MOUSE, 0, 1);
747 // Nothing changes since 2nd drag is ignored.
748 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
750 button_host->PointerReleasedOnButton(dragged_button_touch,
751 internal::LauncherButtonHost::TOUCH,
752 false);
753 ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
756 // Confirm that item status changes are reflected in the buttons.
757 TEST_F(LauncherViewTest, LauncherItemStatus) {
758 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
759 test_api_->GetButtonCount());
761 // Add tabbed browser.
762 LauncherID last_added = AddTabbedBrowser();
763 LauncherItem item = GetItemByID(last_added);
764 int index = model_->ItemIndexByID(last_added);
765 internal::LauncherButton* button = GetButtonByID(last_added);
766 ASSERT_EQ(internal::LauncherButton::STATE_RUNNING, button->state());
767 item.status = ash::STATUS_ACTIVE;
768 model_->Set(index, item);
769 ASSERT_EQ(internal::LauncherButton::STATE_ACTIVE, button->state());
770 item.status = ash::STATUS_ATTENTION;
771 model_->Set(index, item);
772 ASSERT_EQ(internal::LauncherButton::STATE_ATTENTION, button->state());
775 TEST_F(LauncherViewTest, LauncherItemPositionReflectedOnStateChanged) {
776 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
777 test_api_->GetButtonCount());
779 // Add 2 items to the launcher.
780 LauncherID item1_id = AddTabbedBrowser();
781 LauncherID item2_id = AddPlatformAppNoWait();
782 internal::LauncherButton* item1_button = GetButtonByID(item1_id);
783 internal::LauncherButton* item2_button = GetButtonByID(item2_id);
785 internal::LauncherButton::State state_mask =
786 static_cast<internal::LauncherButton::State>
787 (internal::LauncherButton::STATE_NORMAL |
788 internal::LauncherButton::STATE_HOVERED |
789 internal::LauncherButton::STATE_RUNNING |
790 internal::LauncherButton::STATE_ACTIVE |
791 internal::LauncherButton::STATE_ATTENTION |
792 internal::LauncherButton::STATE_FOCUSED);
794 // Clear the button states.
795 item1_button->ClearState(state_mask);
796 item2_button->ClearState(state_mask);
798 // Since default alignment in tests is bottom, state is reflected in y-axis.
799 ASSERT_EQ(item1_button->GetIconBounds().y(),
800 item2_button->GetIconBounds().y());
801 item1_button->AddState(internal::LauncherButton::STATE_HOVERED);
802 ASSERT_NE(item1_button->GetIconBounds().y(),
803 item2_button->GetIconBounds().y());
804 item1_button->ClearState(internal::LauncherButton::STATE_HOVERED);
806 // Enable the alternate shelf layout.
807 CommandLine::ForCurrentProcess()->AppendSwitch(
808 ash::switches::kAshUseAlternateShelfLayout);
809 launcher_view_->Layout();
811 // Since default alignment in tests is bottom, state is reflected in y-axis.
812 // In alternate shelf layout there is no visible hovered state.
813 ASSERT_EQ(item1_button->GetIconBounds().y(),
814 item2_button->GetIconBounds().y());
815 item1_button->AddState(internal::LauncherButton::STATE_HOVERED);
816 ASSERT_EQ(item1_button->GetIconBounds().y(),
817 item2_button->GetIconBounds().y());
820 // Confirm that item status changes are reflected in the buttons
821 // for platform apps.
822 TEST_F(LauncherViewTest, LauncherItemStatusPlatformApp) {
823 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
824 test_api_->GetButtonCount());
826 // Add tabbed browser.
827 LauncherID last_added = AddPlatformApp();
828 LauncherItem item = GetItemByID(last_added);
829 int index = model_->ItemIndexByID(last_added);
830 internal::LauncherButton* button = GetButtonByID(last_added);
831 ASSERT_EQ(internal::LauncherButton::STATE_RUNNING, button->state());
832 item.status = ash::STATUS_ACTIVE;
833 model_->Set(index, item);
834 ASSERT_EQ(internal::LauncherButton::STATE_ACTIVE, button->state());
835 item.status = ash::STATUS_ATTENTION;
836 model_->Set(index, item);
837 ASSERT_EQ(internal::LauncherButton::STATE_ATTENTION, button->state());
840 // Confirm that launcher item bounds are correctly updated on shelf changes.
841 TEST_F(LauncherViewTest, LauncherItemBoundsCheck) {
842 internal::ShelfLayoutManager* shelf_layout_manager =
843 Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
844 VerifyLauncherItemBoundsAreValid();
845 shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
846 test_api_->RunMessageLoopUntilAnimationsDone();
847 VerifyLauncherItemBoundsAreValid();
848 shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
849 test_api_->RunMessageLoopUntilAnimationsDone();
850 VerifyLauncherItemBoundsAreValid();
853 TEST_F(LauncherViewTest, LauncherTooltipTest) {
854 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
855 test_api_->GetButtonCount());
857 // Prepare some items to the launcher.
858 LauncherID app_button_id = AddAppShortcut();
859 LauncherID tab_button_id = AddTabbedBrowser();
861 internal::LauncherButton* app_button = GetButtonByID(app_button_id);
862 internal::LauncherButton* tab_button = GetButtonByID(tab_button_id);
864 internal::LauncherButtonHost* button_host = launcher_view_;
865 internal::LauncherTooltipManager* tooltip_manager =
866 launcher_view_->tooltip_manager();
868 button_host->MouseEnteredButton(app_button);
869 // There's a delay to show the tooltip, so it's not visible yet.
870 EXPECT_FALSE(tooltip_manager->IsVisible());
871 EXPECT_EQ(app_button, GetTooltipAnchorView());
873 ShowTooltip();
874 EXPECT_TRUE(tooltip_manager->IsVisible());
876 // Once it's visible, it keeps visibility and is pointing to the same
877 // item.
878 button_host->MouseExitedButton(app_button);
879 EXPECT_TRUE(tooltip_manager->IsVisible());
880 EXPECT_EQ(app_button, GetTooltipAnchorView());
882 // When entered to another item, it switches to the new item. There is no
883 // delay for the visibility.
884 button_host->MouseEnteredButton(tab_button);
885 EXPECT_TRUE(tooltip_manager->IsVisible());
886 EXPECT_EQ(tab_button, GetTooltipAnchorView());
888 button_host->MouseExitedButton(tab_button);
889 tooltip_manager->Close();
891 // Next time: enter app_button -> move immediately to tab_button.
892 button_host->MouseEnteredButton(app_button);
893 button_host->MouseExitedButton(app_button);
894 button_host->MouseEnteredButton(tab_button);
895 EXPECT_FALSE(tooltip_manager->IsVisible());
896 EXPECT_EQ(tab_button, GetTooltipAnchorView());
899 TEST_F(LauncherViewTest, ShouldHideTooltipTest) {
900 LauncherID app_button_id = AddAppShortcut();
901 LauncherID tab_button_id = AddTabbedBrowser();
903 // The tooltip shouldn't hide if the mouse is on normal buttons.
904 for (int i = 0; i < test_api_->GetButtonCount(); i++) {
905 internal::LauncherButton* button = test_api_->GetButton(i);
906 if (!button)
907 continue;
909 EXPECT_FALSE(launcher_view_->ShouldHideTooltip(
910 button->GetMirroredBounds().CenterPoint()))
911 << "LauncherView tries to hide on button " << i;
914 // The tooltip should not hide on the app-list button.
915 views::View* app_list_button = launcher_view_->GetAppListButtonView();
916 EXPECT_FALSE(launcher_view_->ShouldHideTooltip(
917 app_list_button->GetMirroredBounds().CenterPoint()));
919 // The tooltip shouldn't hide if the mouse is in the gap between two buttons.
920 gfx::Rect app_button_rect = GetButtonByID(app_button_id)->GetMirroredBounds();
921 gfx::Rect tab_button_rect = GetButtonByID(tab_button_id)->GetMirroredBounds();
922 ASSERT_FALSE(app_button_rect.Intersects(tab_button_rect));
923 EXPECT_FALSE(launcher_view_->ShouldHideTooltip(
924 gfx::UnionRects(app_button_rect, tab_button_rect).CenterPoint()));
926 // The tooltip should hide if it's outside of all buttons.
927 gfx::Rect all_area;
928 for (int i = 0; i < test_api_->GetButtonCount(); i++) {
929 internal::LauncherButton* button = test_api_->GetButton(i);
930 if (!button)
931 continue;
933 all_area.Union(button->GetMirroredBounds());
935 all_area.Union(launcher_view_->GetAppListButtonView()->GetMirroredBounds());
936 EXPECT_FALSE(launcher_view_->ShouldHideTooltip(all_area.origin()));
937 EXPECT_FALSE(launcher_view_->ShouldHideTooltip(
938 gfx::Point(all_area.right() - 1, all_area.bottom() - 1)));
939 EXPECT_TRUE(launcher_view_->ShouldHideTooltip(
940 gfx::Point(all_area.right(), all_area.y())));
941 EXPECT_TRUE(launcher_view_->ShouldHideTooltip(
942 gfx::Point(all_area.x() - 1, all_area.y())));
943 EXPECT_TRUE(launcher_view_->ShouldHideTooltip(
944 gfx::Point(all_area.x(), all_area.y() - 1)));
945 EXPECT_TRUE(launcher_view_->ShouldHideTooltip(
946 gfx::Point(all_area.x(), all_area.bottom())));
949 TEST_F(LauncherViewTest, ShouldHideTooltipWithAppListWindowTest) {
950 Shell::GetInstance()->ToggleAppList(NULL);
951 ASSERT_TRUE(Shell::GetInstance()->GetAppListWindow());
953 // The tooltip shouldn't hide if the mouse is on normal buttons.
954 for (int i = 1; i < test_api_->GetButtonCount(); i++) {
955 internal::LauncherButton* button = test_api_->GetButton(i);
956 if (!button)
957 continue;
959 EXPECT_FALSE(launcher_view_->ShouldHideTooltip(
960 button->GetMirroredBounds().CenterPoint()))
961 << "LauncherView tries to hide on button " << i;
964 // The tooltip should hide on the app-list button.
965 views::View* app_list_button = launcher_view_->GetAppListButtonView();
966 EXPECT_TRUE(launcher_view_->ShouldHideTooltip(
967 app_list_button->GetMirroredBounds().CenterPoint()));
970 // Test that by moving the mouse cursor off the button onto the bubble it closes
971 // the bubble.
972 TEST_F(LauncherViewTest, ShouldHideTooltipWhenHoveringOnTooltip) {
973 internal::LauncherTooltipManager* tooltip_manager =
974 launcher_view_->tooltip_manager();
975 tooltip_manager->CreateZeroDelayTimerForTest();
976 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
978 // Move the mouse off any item and check that no tooltip is shown.
979 generator.MoveMouseTo(gfx::Point(0, 0));
980 EXPECT_FALSE(tooltip_manager->IsVisible());
982 // Move the mouse over the button and check that it is visible.
983 views::View* app_list_button = launcher_view_->GetAppListButtonView();
984 gfx::Rect bounds = app_list_button->GetBoundsInScreen();
985 generator.MoveMouseTo(bounds.CenterPoint());
986 // Wait for the timer to go off.
987 RunAllPendingInMessageLoop();
988 EXPECT_TRUE(tooltip_manager->IsVisible());
990 // Move the mouse cursor slightly to the right of the item. The tooltip should
991 // stay open.
992 generator.MoveMouseBy(-(bounds.width() / 2 + 5), 0);
993 // Make sure there is no delayed close.
994 RunAllPendingInMessageLoop();
995 EXPECT_TRUE(tooltip_manager->IsVisible());
997 // Move back - it should still stay open.
998 generator.MoveMouseBy(bounds.width() / 2 + 5, 0);
999 // Make sure there is no delayed close.
1000 RunAllPendingInMessageLoop();
1001 EXPECT_TRUE(tooltip_manager->IsVisible());
1003 // Now move the mouse cursor slightly above the item - so that it is over the
1004 // tooltip bubble. Now it should disappear.
1005 generator.MoveMouseBy(0, -(bounds.height() / 2 + 5));
1006 // Wait until the delayed close kicked in.
1007 RunAllPendingInMessageLoop();
1008 EXPECT_FALSE(tooltip_manager->IsVisible());
1011 // Resizing launcher view while an add animation without fade-in is running,
1012 // which happens when overflow happens. App list button should end up in its
1013 // new ideal bounds.
1014 TEST_F(LauncherViewTest, ResizeDuringOverflowAddAnimation) {
1015 // All buttons should be visible.
1016 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1017 test_api_->GetButtonCount());
1019 // Add buttons until overflow. Let the non-overflow add animations finish but
1020 // leave the last running.
1021 int items_added = 0;
1022 AddTabbedBrowserNoWait();
1023 while (!test_api_->IsOverflowButtonVisible()) {
1024 test_api_->RunMessageLoopUntilAnimationsDone();
1025 AddTabbedBrowserNoWait();
1026 ++items_added;
1027 ASSERT_LT(items_added, 10000);
1030 // Resize launcher view with that animation running and stay overflown.
1031 gfx::Rect bounds = launcher_view_->bounds();
1032 bounds.set_width(bounds.width() - kLauncherPreferredSize);
1033 launcher_view_->SetBoundsRect(bounds);
1034 ASSERT_TRUE(test_api_->IsOverflowButtonVisible());
1036 // Finish the animation.
1037 test_api_->RunMessageLoopUntilAnimationsDone();
1039 // App list button should ends up in its new ideal bounds.
1040 const int app_list_button_index = test_api_->GetButtonCount() - 1;
1041 const gfx::Rect& app_list_ideal_bounds =
1042 test_api_->GetIdealBoundsByIndex(app_list_button_index);
1043 const gfx::Rect& app_list_bounds =
1044 test_api_->GetBoundsByIndex(app_list_button_index);
1045 EXPECT_EQ(app_list_bounds, app_list_ideal_bounds);
1048 // Check that the first item in the list follows Fitt's law by including the
1049 // first pixel and being therefore bigger then the others.
1050 TEST_F(LauncherViewTest, CheckFittsLaw) {
1051 // All buttons should be visible.
1052 ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1,
1053 test_api_->GetButtonCount());
1054 gfx::Rect ideal_bounds_0 = test_api_->GetIdealBoundsByIndex(0);
1055 gfx::Rect ideal_bounds_1 = test_api_->GetIdealBoundsByIndex(1);
1056 EXPECT_GT(ideal_bounds_0.width(), ideal_bounds_1.width());
1059 INSTANTIATE_TEST_CASE_P(LtrRtl, LauncherViewTextDirectionTest, testing::Bool());
1061 } // namespace test
1062 } // namespace ash