apps_grid_view_test_api.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. #include "ash/app_list/views/apps_grid_view_test_api.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "ash/app_list/paged_view_structure.h"
  8. #include "ash/app_list/views/app_drag_icon_proxy.h"
  9. #include "ash/app_list/views/app_list_item_view.h"
  10. #include "ash/app_list/views/apps_grid_view.h"
  11. #include "base/run_loop.h"
  12. #include "build/build_config.h"
  13. #include "ui/aura/window.h"
  14. #include "ui/events/event.h"
  15. #include "ui/events/test/event_generator.h"
  16. #include "ui/views/animation/bounds_animator.h"
  17. #include "ui/views/animation/bounds_animator_observer.h"
  18. #include "ui/views/view.h"
  19. #include "ui/views/widget/widget.h"
  20. namespace ash {
  21. namespace test {
  22. namespace {
  23. class BoundsAnimatorWaiter : public views::BoundsAnimatorObserver {
  24. public:
  25. explicit BoundsAnimatorWaiter(views::BoundsAnimator* animator)
  26. : animator_(animator) {
  27. animator->AddObserver(this);
  28. }
  29. BoundsAnimatorWaiter(const BoundsAnimatorWaiter&) = delete;
  30. BoundsAnimatorWaiter& operator=(const BoundsAnimatorWaiter&) = delete;
  31. ~BoundsAnimatorWaiter() override { animator_->RemoveObserver(this); }
  32. void Wait() {
  33. if (!animator_->IsAnimating())
  34. return;
  35. run_loop_ = std::make_unique<base::RunLoop>();
  36. run_loop_->Run();
  37. }
  38. private:
  39. // views::BoundsAnimatorObserver:
  40. void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override {}
  41. void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override {
  42. if (run_loop_)
  43. run_loop_->Quit();
  44. }
  45. views::BoundsAnimator* animator_;
  46. std::unique_ptr<base::RunLoop> run_loop_;
  47. };
  48. } // namespace
  49. AppsGridViewTestApi::AppsGridViewTestApi(AppsGridView* view) : view_(view) {}
  50. AppsGridViewTestApi::~AppsGridViewTestApi() = default;
  51. views::View* AppsGridViewTestApi::GetViewAtModelIndex(int index) const {
  52. return view_->view_model_.view_at(index);
  53. }
  54. void AppsGridViewTestApi::LayoutToIdealBounds() {
  55. if (view_->reorder_timer_.IsRunning()) {
  56. view_->reorder_timer_.Stop();
  57. view_->OnReorderTimer();
  58. }
  59. view_->bounds_animator_->Cancel();
  60. view_->Layout();
  61. }
  62. gfx::Rect AppsGridViewTestApi::GetItemTileRectOnCurrentPageAt(int row,
  63. int col) const {
  64. int slot = row * (view_->cols()) + col;
  65. gfx::Rect bounds_in_ltr =
  66. view_->GetExpectedTileBounds(GridIndex(view_->GetSelectedPage(), slot));
  67. // `GetExpectedTileBounds()` returns expected bounds for item at provided grid
  68. // index in LTR UI. Make sure this method returns mirrored bounds in RTL UI.
  69. return view_->GetMirroredRect(bounds_in_ltr);
  70. }
  71. void AppsGridViewTestApi::PressItemAt(int index) {
  72. GetViewAtModelIndex(index)->OnKeyPressed(
  73. ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE));
  74. }
  75. size_t AppsGridViewTestApi::TilesPerPage(int page) const {
  76. return view_->TilesPerPage(page);
  77. }
  78. int AppsGridViewTestApi::AppsOnPage(int page) const {
  79. return view_->GetNumberOfItemsOnPage(page);
  80. }
  81. AppListItemView* AppsGridViewTestApi::GetViewAtIndex(GridIndex index) const {
  82. return view_->GetViewAtIndex(index);
  83. }
  84. AppListItemView* AppsGridViewTestApi::GetViewAtVisualIndex(int page,
  85. int slot) const {
  86. const std::vector<std::vector<AppListItemView*>>& view_structure =
  87. view_->view_structure_.pages();
  88. if (page >= static_cast<int>(view_structure.size()) ||
  89. slot >= static_cast<int>(view_structure[page].size())) {
  90. return nullptr;
  91. }
  92. return view_structure[page][slot];
  93. }
  94. const std::string& AppsGridViewTestApi::GetNameAtVisualIndex(int page,
  95. int slot) const {
  96. return GetViewAtVisualIndex(page, slot)->item()->name();
  97. }
  98. gfx::Rect AppsGridViewTestApi::GetItemTileRectAtVisualIndex(int page,
  99. int slot) const {
  100. // `GetExpectedTileBounds()` returns expected bounds for item at provided grid
  101. // index in LTR UI. Make sure this method returns mirrored bounds in RTL UI.
  102. return view_->GetMirroredRect(
  103. view_->GetExpectedTileBounds(GridIndex(page, slot)));
  104. }
  105. void AppsGridViewTestApi::WaitForItemMoveAnimationDone() {
  106. BoundsAnimatorWaiter waiter(view_->bounds_animator_.get());
  107. waiter.Wait();
  108. }
  109. void AppsGridViewTestApi::FireReorderTimerAndWaitForAnimationDone() {
  110. base::OneShotTimer* timer = &view_->reorder_timer_;
  111. if (timer->IsRunning())
  112. timer->FireNow();
  113. WaitForItemMoveAnimationDone();
  114. }
  115. void AppsGridViewTestApi::FireFolderItemReparentTimer() {
  116. view_->FireFolderItemReparentTimerForTest();
  117. }
  118. gfx::Rect AppsGridViewTestApi::GetDragIconBoundsInAppsGridView() {
  119. if (!view_->drag_icon_proxy_)
  120. return gfx::Rect();
  121. gfx::Rect icon_bounds_in_screen =
  122. view_->drag_icon_proxy_->GetBoundsInScreen();
  123. if (icon_bounds_in_screen.IsEmpty())
  124. return gfx::Rect();
  125. gfx::Point icon_origin = icon_bounds_in_screen.origin();
  126. views::View::ConvertPointFromScreen(view_, &icon_origin);
  127. return gfx::Rect(icon_origin, icon_bounds_in_screen.size());
  128. }
  129. ui::Layer* AppsGridViewTestApi::GetDragIconLayer() {
  130. if (!view_->drag_icon_proxy_)
  131. return nullptr;
  132. return view_->drag_icon_proxy_->GetImageLayerForTesting();
  133. }
  134. void AppsGridViewTestApi::ReorderItemByDragAndDrop(int source_index,
  135. int target_index) {
  136. if (source_index == target_index)
  137. return;
  138. ui::test::EventGenerator event_generator(
  139. view_->GetWidget()->GetNativeView()->GetRootWindow());
  140. ash::AppListItemView* dragged_view =
  141. view_->view_model()->view_at(source_index);
  142. event_generator.MoveMouseTo(dragged_view->GetBoundsInScreen().CenterPoint());
  143. event_generator.PressLeftButton();
  144. dragged_view->FireMouseDragTimerForTest();
  145. // Calculate the move target location. If `source_index` is to the left of
  146. // `target_index`, the item should be moved to the right of the target slot
  147. // in order to trigger apps reorder; otherwise, the item should be moved to
  148. // the left.
  149. const gfx::Rect target_view_screen_bounds =
  150. view_->view_model()->view_at(target_index)->GetBoundsInScreen();
  151. constexpr int offset = 10;
  152. const int target_location_x =
  153. (source_index < target_index ? target_view_screen_bounds.right() + offset
  154. : target_view_screen_bounds.x() - offset);
  155. const gfx::Point target_move_location(
  156. target_location_x, target_view_screen_bounds.CenterPoint().y());
  157. event_generator.MoveMouseTo(target_move_location);
  158. FireReorderTimerAndWaitForAnimationDone();
  159. event_generator.ReleaseLeftButton();
  160. }
  161. } // namespace test
  162. } // namespace ash