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