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