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