scrollable_apps_grid_view_unittest.cc 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. // Copyright 2021 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/scrollable_apps_grid_view.h"
  5. #include <limits>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "ash/app_list/app_list_controller_impl.h"
  10. #include "ash/app_list/model/app_list_folder_item.h"
  11. #include "ash/app_list/model/app_list_item.h"
  12. #include "ash/app_list/model/app_list_item_list.h"
  13. #include "ash/app_list/model/app_list_model.h"
  14. #include "ash/app_list/model/app_list_test_model.h"
  15. #include "ash/app_list/paged_view_structure.h"
  16. #include "ash/app_list/test/app_list_test_helper.h"
  17. #include "ash/app_list/test_app_list_client.h"
  18. #include "ash/app_list/views/app_list_folder_view.h"
  19. #include "ash/app_list/views/app_list_item_view.h"
  20. #include "ash/app_list/views/apps_grid_view_test_api.h"
  21. #include "ash/app_list/views/search_box_view.h"
  22. #include "ash/constants/ash_features.h"
  23. #include "ash/public/cpp/app_list/app_list_config.h"
  24. #include "ash/public/cpp/shelf_item_delegate.h"
  25. #include "ash/public/cpp/shelf_model.h"
  26. #include "ash/public/cpp/test/test_shelf_item_delegate.h"
  27. #include "ash/shelf/shelf_view.h"
  28. #include "ash/shell.h"
  29. #include "ash/test/ash_test_base.h"
  30. #include "base/test/metrics/histogram_tester.h"
  31. #include "base/test/scoped_feature_list.h"
  32. #include "base/test/task_environment.h"
  33. #include "ui/views/controls/scroll_view.h"
  34. #include "ui/views/controls/textfield/textfield.h"
  35. #include "ui/views/widget/widget.h"
  36. namespace ash {
  37. namespace {
  38. class ShelfItemFactoryFake : public ShelfModel::ShelfItemFactory {
  39. public:
  40. virtual ~ShelfItemFactoryFake() = default;
  41. bool CreateShelfItemForAppId(
  42. const std::string& app_id,
  43. ShelfItem* item,
  44. std::unique_ptr<ShelfItemDelegate>* delegate) override {
  45. *item = ShelfItem();
  46. item->id = ShelfID(app_id);
  47. *delegate = std::make_unique<TestShelfItemDelegate>(item->id);
  48. return true;
  49. }
  50. };
  51. } // namespace
  52. class ScrollableAppsGridViewTest : public AshTestBase {
  53. public:
  54. ScrollableAppsGridViewTest()
  55. : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
  56. scoped_feature_list_.InitAndEnableFeature(features::kProductivityLauncher);
  57. }
  58. ~ScrollableAppsGridViewTest() override = default;
  59. void SetUp() override {
  60. AshTestBase::SetUp();
  61. app_list_test_model_ = std::make_unique<test::AppListTestModel>();
  62. search_model_ = std::make_unique<SearchModel>();
  63. Shell::Get()->app_list_controller()->SetActiveModel(
  64. /*profile_id=*/1, app_list_test_model_.get(), search_model_.get());
  65. shelf_item_factory_ = std::make_unique<ShelfItemFactoryFake>();
  66. ShelfModel::Get()->SetShelfItemFactory(shelf_item_factory_.get());
  67. }
  68. void TearDown() override {
  69. ShelfModel::Get()->SetShelfItemFactory(nullptr);
  70. AshTestBase::TearDown();
  71. }
  72. test::AppListTestModel::AppListTestItem* AddAppListItem(
  73. const std::string& id) {
  74. return app_list_test_model_->CreateAndAddItem(id);
  75. }
  76. void PopulateApps(int n) { app_list_test_model_->PopulateApps(n); }
  77. void DeleteApps(int n) {
  78. AppListItemList* item_list = app_list_test_model_->top_level_item_list();
  79. for (int i = 0; i < n; i++) {
  80. app_list_test_model_->DeleteItem(item_list->item_at(0)->id());
  81. }
  82. }
  83. AppListFolderItem* CreateAndPopulateFolderWithApps(int n) {
  84. return app_list_test_model_->CreateAndPopulateFolderWithApps(n);
  85. }
  86. void SimulateKeyPress(ui::KeyboardCode key_code, int flags = ui::EF_NONE) {
  87. GetEventGenerator()->PressKey(key_code, flags);
  88. }
  89. void SimulateKeyReleased(ui::KeyboardCode key_code, int flags = ui::EF_NONE) {
  90. GetEventGenerator()->ReleaseKey(key_code, flags);
  91. }
  92. void ShowAppList() {
  93. GetAppListTestHelper()->ShowAppList();
  94. apps_grid_view_ = GetAppListTestHelper()->GetScrollableAppsGridView();
  95. scroll_view_ = apps_grid_view_->scroll_view_for_test();
  96. }
  97. AppListItemView* StartDragOnItemViewAt(int item_index) {
  98. AppListItemView* item = apps_grid_view_->GetItemViewAt(item_index);
  99. auto* generator = GetEventGenerator();
  100. generator->MoveMouseTo(item->GetBoundsInScreen().CenterPoint());
  101. generator->PressLeftButton();
  102. item->FireMouseDragTimerForTest();
  103. return item;
  104. }
  105. AppListItemView* StartDragOnItemInFolderAt(int item_index) {
  106. DCHECK(GetAppListTestHelper()->IsInFolderView());
  107. auto* folder_view = GetAppListTestHelper()->GetBubbleFolderView();
  108. AppListItemView* item =
  109. folder_view->items_grid_view()->GetItemViewAt(item_index);
  110. auto* generator = GetEventGenerator();
  111. generator->MoveMouseTo(item->GetBoundsInScreen().CenterPoint());
  112. generator->PressLeftButton();
  113. item->FireMouseDragTimerForTest();
  114. return item;
  115. }
  116. void DragItemOutOfFolder() {
  117. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  118. auto* folder_view = GetAppListTestHelper()->GetBubbleFolderView();
  119. ASSERT_TRUE(folder_view->items_grid_view()->has_dragged_item());
  120. gfx::Point outside_view =
  121. folder_view->GetBoundsInScreen().bottom_right() + gfx::Vector2d(10, 10);
  122. GetEventGenerator()->MoveMouseTo(outside_view);
  123. folder_view->items_grid_view()->FireFolderItemReparentTimerForTest();
  124. }
  125. ScrollableAppsGridView* GetScrollableAppsGridView() {
  126. return GetAppListTestHelper()->GetScrollableAppsGridView();
  127. }
  128. // Verifies the visible item index range.
  129. bool IsIndexRangeExpected(size_t first_index, size_t last_index) {
  130. const absl::optional<AppsGridView::VisibleItemIndexRange> index_range =
  131. apps_grid_view_->GetVisibleItemIndexRange();
  132. return index_range->first_index == first_index &&
  133. index_range->last_index == last_index;
  134. }
  135. void AddPageBreakItem() { GetAppListTestHelper()->AddPageBreakItem(); }
  136. base::test::ScopedFeatureList scoped_feature_list_;
  137. std::unique_ptr<test::AppListTestModel> app_list_test_model_;
  138. std::unique_ptr<SearchModel> search_model_;
  139. std::unique_ptr<ShelfItemFactoryFake> shelf_item_factory_;
  140. // Cache some view pointers to make the tests more concise.
  141. ScrollableAppsGridView* apps_grid_view_ = nullptr;
  142. views::ScrollView* scroll_view_ = nullptr;
  143. };
  144. TEST_F(ScrollableAppsGridViewTest, PageBreaksDoNotCauseExtraRowsInLayout) {
  145. AddAppListItem("1");
  146. AddAppListItem("2");
  147. AddAppListItem("3");
  148. AddAppListItem("4");
  149. AddPageBreakItem();
  150. AddAppListItem("5");
  151. ShowAppList();
  152. ScrollableAppsGridView* view = GetScrollableAppsGridView();
  153. const int tile_height = view->app_list_config()->grid_tile_height();
  154. const gfx::Size grid_size = view->GetTileGridSize();
  155. // The layout is one tile tall because it has only one row.
  156. EXPECT_EQ(grid_size.height(), tile_height);
  157. }
  158. TEST_F(ScrollableAppsGridViewTest, ClickOnApp) {
  159. AddAppListItem("id");
  160. ShowAppList();
  161. // Click on the first icon.
  162. ScrollableAppsGridView* view = GetScrollableAppsGridView();
  163. views::View* icon = view->GetItemViewAt(0);
  164. GetEventGenerator()->MoveMouseTo(icon->GetBoundsInScreen().CenterPoint());
  165. GetEventGenerator()->ClickLeftButton();
  166. // The item was activated.
  167. EXPECT_EQ(1, GetTestAppListClient()->activate_item_count());
  168. EXPECT_EQ("id", GetTestAppListClient()->activate_item_last_id());
  169. }
  170. TEST_F(ScrollableAppsGridViewTest, DragApp) {
  171. base::HistogramTester histogram_tester;
  172. AddAppListItem("id1");
  173. AddAppListItem("id2");
  174. ShowAppList();
  175. // Start dragging the first item.
  176. StartDragOnItemViewAt(0);
  177. // Drag to the right of the second item.
  178. gfx::Size tile_size = apps_grid_view_->GetTotalTileSize(/*page=*/0);
  179. auto* generator = GetEventGenerator();
  180. generator->MoveMouseBy(tile_size.width() * 2, 0);
  181. generator->ReleaseLeftButton();
  182. // The item was not activated.
  183. EXPECT_EQ(0, GetTestAppListClient()->activate_item_count());
  184. // Items were reordered.
  185. AppListItemList* item_list = app_list_test_model_->top_level_item_list();
  186. ASSERT_EQ(2u, item_list->item_count());
  187. EXPECT_EQ("id2", item_list->item_at(0)->id());
  188. EXPECT_EQ("id1", item_list->item_at(1)->id());
  189. // Reordering apps is recorded in the histogram tester.
  190. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  191. kReorderByDragInTopLevel, 1);
  192. }
  193. TEST_F(ScrollableAppsGridViewTest, SearchBoxHasFocusAfterDrag) {
  194. PopulateApps(2);
  195. ShowAppList();
  196. // Drag the first item to the right.
  197. AppListItemView* item = StartDragOnItemViewAt(0);
  198. GetEventGenerator()->MoveMouseBy(250, 0);
  199. GetEventGenerator()->ReleaseLeftButton();
  200. // The item does not have focus.
  201. EXPECT_FALSE(item->HasFocus());
  202. EXPECT_FALSE(apps_grid_view_->IsSelectedView(item));
  203. // The search box has focus.
  204. auto* search_box_view = GetAppListTestHelper()->GetBubbleSearchBoxView();
  205. EXPECT_TRUE(search_box_view->search_box()->HasFocus());
  206. EXPECT_TRUE(search_box_view->is_search_box_active());
  207. }
  208. TEST_F(ScrollableAppsGridViewTest, ItemIndicesForMove) {
  209. AddAppListItem("aaa"); // App list item index 0, visual index 0,0.
  210. AddPageBreakItem(); // Not visible.
  211. AddAppListItem("bbb"); // App list item index 2, visual index 0,1.
  212. AddPageBreakItem(); // Not visible.
  213. AddAppListItem("ccc"); // App list item index 4, visual index 0,2.
  214. ShowAppList();
  215. auto* view = GetScrollableAppsGridView();
  216. PagedViewStructure* structure =
  217. test::AppsGridViewTestApi(view).GetPagedViewStructure();
  218. // The last visual index to add an item is 0,3.
  219. EXPECT_EQ(GridIndex(0, 3), structure->GetLastTargetIndex());
  220. EXPECT_EQ(GridIndex(0, 3), structure->GetLastTargetIndexOfPage(0));
  221. // During a drag, the last visual index to add an item is 0,2.
  222. StartDragOnItemViewAt(0);
  223. EXPECT_EQ(GridIndex(0, 2), structure->GetLastTargetIndex());
  224. EXPECT_EQ(GridIndex(0, 2), structure->GetLastTargetIndexOfPage(0));
  225. GetEventGenerator()->ReleaseLeftButton();
  226. // Visual index directly maps to target index in "view model".
  227. EXPECT_EQ(0, structure->GetTargetModelIndexForMove(nullptr, GridIndex(0, 0)));
  228. EXPECT_EQ(1, structure->GetTargetModelIndexForMove(nullptr, GridIndex(0, 1)));
  229. EXPECT_EQ(2, structure->GetTargetModelIndexForMove(nullptr, GridIndex(0, 2)));
  230. EXPECT_EQ(3, structure->GetTargetModelIndexForMove(nullptr, GridIndex(0, 3)));
  231. // Target is the front.
  232. EXPECT_EQ(0,
  233. structure->GetTargetItemListIndexForMove(nullptr, GridIndex(0, 0)));
  234. // Target is after "aaa".
  235. EXPECT_EQ(1,
  236. structure->GetTargetItemListIndexForMove(nullptr, GridIndex(0, 1)));
  237. // Target is after "aaa" + break + "bbb".
  238. EXPECT_EQ(3,
  239. structure->GetTargetItemListIndexForMove(nullptr, GridIndex(0, 2)));
  240. // Target is after "aaa" + break + "bbb" + break + "ccc".
  241. EXPECT_EQ(5,
  242. structure->GetTargetItemListIndexForMove(nullptr, GridIndex(0, 3)));
  243. }
  244. TEST_F(ScrollableAppsGridViewTest, DragAppAfterScrollingDown) {
  245. // Simulate data from another device that has a page break after 20 items.
  246. PopulateApps(20);
  247. AddPageBreakItem();
  248. AddAppListItem("aaa");
  249. AddAppListItem("bbb");
  250. ShowAppList();
  251. // "aaa" and "bbb" are the last two items.
  252. AppListItemList* item_list = app_list_test_model_->top_level_item_list();
  253. ASSERT_EQ(23u, item_list->item_count());
  254. ASSERT_EQ("aaa", item_list->item_at(21)->id());
  255. ASSERT_EQ("bbb", item_list->item_at(22)->id());
  256. // Scroll down to the "aaa" item.
  257. auto* apps_grid_view = GetScrollableAppsGridView();
  258. AppListItemView* item = apps_grid_view->GetItemViewAt(20);
  259. ASSERT_EQ("aaa", item->item()->id());
  260. item->ScrollViewToVisible();
  261. // Drag the "aaa" item to the right.
  262. auto* generator = GetEventGenerator();
  263. generator->MoveMouseTo(item->GetBoundsInScreen().CenterPoint());
  264. generator->PressLeftButton();
  265. item->FireMouseDragTimerForTest();
  266. gfx::Size tile_size = apps_grid_view->GetTotalTileSize(/*page=*/0);
  267. generator->MoveMouseBy(tile_size.width() * 2, 0);
  268. generator->ReleaseLeftButton();
  269. // The last 2 items were reordered.
  270. EXPECT_EQ("bbb", item_list->item_at(21)->id()) << item_list->ToString();
  271. EXPECT_EQ("aaa", item_list->item_at(22)->id()) << item_list->ToString();
  272. }
  273. TEST_F(ScrollableAppsGridViewTest, AutoScrollDown) {
  274. PopulateApps(30);
  275. ShowAppList();
  276. // Scroll view starts at the top.
  277. const int initial_scroll_offset = scroll_view_->GetVisibleRect().y();
  278. EXPECT_EQ(initial_scroll_offset, 0);
  279. // Drag an item into the bottom auto-scroll margin.
  280. StartDragOnItemViewAt(0);
  281. auto* generator = GetEventGenerator();
  282. generator->MoveMouseTo(scroll_view_->GetBoundsInScreen().bottom_center());
  283. // The scroll view scrolls immediately.
  284. const int scroll_offset1 = scroll_view_->GetVisibleRect().y();
  285. EXPECT_GT(scroll_offset1, 0);
  286. // Scroll timer is running.
  287. EXPECT_TRUE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  288. // Reordering is paused.
  289. EXPECT_FALSE(apps_grid_view_->reorder_timer_for_test()->IsRunning());
  290. // Holding the mouse in place for a while scrolls down more.
  291. task_environment()->FastForwardBy(base::Milliseconds(100));
  292. const int scroll_offset2 = scroll_view_->GetVisibleRect().y();
  293. EXPECT_GT(scroll_offset2, scroll_offset1);
  294. // Move the mouse back into the (vertical) center of the view (not in the
  295. // scroll margin). Use a point close to a horizontal edge to avoid hitting an
  296. // item bounds (which would trigger reparent instead of reorder timer).
  297. generator->MoveMouseTo(scroll_view_->GetBoundsInScreen().left_center() +
  298. gfx::Vector2d(5, 0));
  299. // Scroll position didn't change, auto-scrolling is stopped, and reordering
  300. // started again.
  301. EXPECT_EQ(scroll_offset2, scroll_view_->GetVisibleRect().y());
  302. EXPECT_FALSE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  303. EXPECT_TRUE(apps_grid_view_->reorder_timer_for_test()->IsRunning());
  304. }
  305. TEST_F(ScrollableAppsGridViewTest, DoesNotAutoScrollUpWhenAtTop) {
  306. PopulateApps(30);
  307. ShowAppList();
  308. // Drag an item into the top auto-scroll margin and wait a while.
  309. StartDragOnItemViewAt(0);
  310. GetEventGenerator()->MoveMouseTo(
  311. scroll_view_->GetBoundsInScreen().top_center());
  312. task_environment()->FastForwardBy(base::Milliseconds(500));
  313. // View did not scroll.
  314. int scroll_offset = scroll_view_->GetVisibleRect().y();
  315. EXPECT_EQ(scroll_offset, 0);
  316. EXPECT_FALSE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  317. }
  318. TEST_F(ScrollableAppsGridViewTest, DoesNotAutoScrollDownWhenAtBottom) {
  319. PopulateApps(30);
  320. ShowAppList();
  321. // Scroll the view to the bottom.
  322. scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(),
  323. std::numeric_limits<int>::max());
  324. int initial_scroll_offset = scroll_view_->GetVisibleRect().y();
  325. // Drag an item into the bottom auto-scroll margin and wait a while.
  326. StartDragOnItemViewAt(29);
  327. GetEventGenerator()->MoveMouseTo(
  328. scroll_view_->GetBoundsInScreen().bottom_center());
  329. task_environment()->FastForwardBy(base::Milliseconds(500));
  330. // View did not scroll.
  331. int scroll_offset = scroll_view_->GetVisibleRect().y();
  332. EXPECT_EQ(scroll_offset, initial_scroll_offset);
  333. EXPECT_FALSE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  334. }
  335. TEST_F(ScrollableAppsGridViewTest, DoesNotAutoScrollWhenDraggedToTheRight) {
  336. PopulateApps(30);
  337. ShowAppList();
  338. // Drag an item outside the bottom-right corner of the scroll view (i.e.
  339. // towards the shelf).
  340. StartDragOnItemViewAt(0);
  341. gfx::Point point = scroll_view_->GetBoundsInScreen().bottom_right();
  342. point.Offset(10, 10);
  343. GetEventGenerator()->MoveMouseTo(point);
  344. task_environment()->FastForwardBy(base::Milliseconds(500));
  345. // View did not scroll.
  346. int scroll_offset = scroll_view_->GetVisibleRect().y();
  347. EXPECT_EQ(scroll_offset, 0);
  348. EXPECT_FALSE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  349. }
  350. TEST_F(ScrollableAppsGridViewTest, DoesNotAutoScrollWhenAboveWidget) {
  351. PopulateApps(30);
  352. ShowAppList();
  353. // Scroll the view to the bottom.
  354. scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(),
  355. std::numeric_limits<int>::max());
  356. int initial_scroll_offset = scroll_view_->GetVisibleRect().y();
  357. // Drag an item above the widget scroll margin.
  358. StartDragOnItemViewAt(29);
  359. gfx::Point point =
  360. scroll_view_->GetWidget()->GetWindowBoundsInScreen().top_center();
  361. point.Offset(0, -10);
  362. GetEventGenerator()->MoveMouseTo(point);
  363. task_environment()->FastForwardBy(base::Milliseconds(500));
  364. // View did not scroll.
  365. int scroll_offset = scroll_view_->GetVisibleRect().y();
  366. EXPECT_EQ(scroll_offset, initial_scroll_offset);
  367. EXPECT_FALSE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  368. }
  369. TEST_F(ScrollableAppsGridViewTest, DoesNotAutoScrollWhenBelowWidget) {
  370. PopulateApps(30);
  371. ShowAppList();
  372. // Drag an item below the widget scroll margin.
  373. StartDragOnItemViewAt(0);
  374. gfx::Point point =
  375. scroll_view_->GetWidget()->GetWindowBoundsInScreen().bottom_center();
  376. point.Offset(0, 10);
  377. GetEventGenerator()->MoveMouseTo(point);
  378. task_environment()->FastForwardBy(base::Milliseconds(500));
  379. // View did not scroll.
  380. int scroll_offset = scroll_view_->GetVisibleRect().y();
  381. EXPECT_EQ(scroll_offset, 0);
  382. EXPECT_FALSE(apps_grid_view_->auto_scroll_timer_for_test()->IsRunning());
  383. }
  384. // Regression test for https://crbug.com/1258954
  385. TEST_F(ScrollableAppsGridViewTest, DragItemIntoEmptySpaceWillReorderToEnd) {
  386. AddAppListItem("id1");
  387. AddAppListItem("id2");
  388. AddAppListItem("id3");
  389. ShowAppList();
  390. // The grid view is taller than the single row of apps, so it can handle drops
  391. // in the empty region.
  392. EXPECT_GT(apps_grid_view_->height(),
  393. apps_grid_view_->GetTileGridSize().height());
  394. // Drag and drop the first item straight down below the first row.
  395. StartDragOnItemViewAt(0);
  396. gfx::Size tile_size = apps_grid_view_->GetTotalTileSize(/*page=*/0);
  397. auto* generator = GetEventGenerator();
  398. generator->MoveMouseBy(0, tile_size.height());
  399. generator->ReleaseLeftButton();
  400. // The first item was reordered to the end.
  401. AppListItemList* item_list = app_list_test_model_->top_level_item_list();
  402. ASSERT_EQ(3u, item_list->item_count());
  403. EXPECT_EQ("id2", item_list->item_at(0)->id());
  404. EXPECT_EQ("id3", item_list->item_at(1)->id());
  405. EXPECT_EQ("id1", item_list->item_at(2)->id());
  406. }
  407. TEST_F(ScrollableAppsGridViewTest, ChangingAppListModelUpdatesAppsGridHeight) {
  408. // Start with 4 rows of 5.
  409. PopulateApps(20);
  410. ShowAppList();
  411. // Adding one row of 5 causes the grid size to expand.
  412. const int height_before_adding = apps_grid_view_->height();
  413. PopulateApps(5);
  414. apps_grid_view_->GetWidget()->LayoutRootViewIfNecessary();
  415. EXPECT_GT(apps_grid_view_->height(), height_before_adding);
  416. // Removing one row of 5 causes the grid size to contract.
  417. const int height_before_removing = apps_grid_view_->height();
  418. DeleteApps(5);
  419. apps_grid_view_->GetWidget()->LayoutRootViewIfNecessary();
  420. EXPECT_LT(apps_grid_view_->height(), height_before_removing);
  421. }
  422. TEST_F(ScrollableAppsGridViewTest, SmallFolderHasCorrectWidth) {
  423. CreateAndPopulateFolderWithApps(2);
  424. ShowAppList();
  425. // Enter the folder view.
  426. LeftClickOn(apps_grid_view_->GetItemViewAt(0));
  427. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  428. auto* folder_view = GetAppListTestHelper()->GetBubbleFolderView();
  429. auto* items_grid_view = folder_view->items_grid_view();
  430. const int tile_width = items_grid_view->app_list_config()->grid_tile_width();
  431. // Spec calls for 8 dips of padding at edges and between tiles.
  432. EXPECT_EQ(folder_view->width(), 8 + tile_width + 8 + tile_width + 8);
  433. // The leftmost item is flush to the left of the grid.
  434. EXPECT_EQ(items_grid_view->GetItemViewAt(0)->bounds().x(), 0);
  435. // The rightmost item is flush to the right of the grid.
  436. EXPECT_EQ(items_grid_view->GetItemViewAt(1)->bounds().right(),
  437. items_grid_view->GetLocalBounds().right());
  438. }
  439. TEST_F(ScrollableAppsGridViewTest, DragItemToReorderInFolderRecordsHistogram) {
  440. base::HistogramTester histogram_tester;
  441. // Create a folder with 3 apps.
  442. AppListFolderItem* folder_item = CreateAndPopulateFolderWithApps(3);
  443. ShowAppList();
  444. // Enter the folder view.
  445. LeftClickOn(apps_grid_view_->GetItemViewAt(0));
  446. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  447. // Drag the first app in the folder.
  448. AppListItemView* item_view = StartDragOnItemInFolderAt(0);
  449. // Drag the item to the third position in the folder.
  450. gfx::Size tile_size = apps_grid_view_->GetTileViewSize();
  451. auto* generator = GetEventGenerator();
  452. generator->MoveMouseBy(0, tile_size.height());
  453. generator->ReleaseLeftButton();
  454. // The item is now reordered in the folder and the reordering is recorded.
  455. EXPECT_EQ(3u, folder_item->ChildItemCount());
  456. EXPECT_EQ(folder_item->item_list()->item_at(2)->id(),
  457. item_view->item()->id());
  458. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  459. kReorderByDragInFolder, 1);
  460. }
  461. TEST_F(ScrollableAppsGridViewTest, DragItemIntoFolderRecordsHistogram) {
  462. base::HistogramTester histogram_tester;
  463. // Create a folder and an app.
  464. AppListFolderItem* folder_item = CreateAndPopulateFolderWithApps(3);
  465. AddAppListItem("dragged_item");
  466. ShowAppList();
  467. // Drag the app in the top level app list into the folder.
  468. StartDragOnItemViewAt(1);
  469. ASSERT_TRUE(apps_grid_view_->GetItemViewAt(0)->item()->is_folder());
  470. auto* generator = GetEventGenerator();
  471. generator->MoveMouseTo(
  472. apps_grid_view_->GetItemViewAt(0)->GetBoundsInScreen().CenterPoint());
  473. generator->ReleaseLeftButton();
  474. // The dragged app is now in the folder and the reordering is recorded.
  475. EXPECT_EQ(4u, folder_item->ChildItemCount());
  476. EXPECT_EQ(folder_item->item_list()->item_at(3)->id(), "dragged_item");
  477. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  478. kMoveByDragIntoFolder, 1);
  479. }
  480. TEST_F(ScrollableAppsGridViewTest, DragItemOutOfFolderRecordsHistogram) {
  481. base::HistogramTester histogram_tester;
  482. // Create a folder with 3 apps.
  483. AppListFolderItem* folder_item = CreateAndPopulateFolderWithApps(3);
  484. ShowAppList();
  485. // Enter the folder view.
  486. LeftClickOn(apps_grid_view_->GetItemViewAt(0));
  487. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  488. // Drag the first app in the folder and move it out of the folder.
  489. AppListItemView* item_view = StartDragOnItemInFolderAt(0);
  490. std::string item_id = item_view->item()->id();
  491. DragItemOutOfFolder();
  492. // Drag the app item to near the expected end position and end the drag.
  493. auto* generator = GetEventGenerator();
  494. generator->MoveMouseTo(
  495. apps_grid_view_->GetItemViewAt(0)->GetBoundsInScreen().right_center() +
  496. gfx::Vector2d(20, 0));
  497. generator->ReleaseLeftButton();
  498. // The folder view should be closed and invisible after releasing the drag.
  499. EXPECT_FALSE(GetAppListTestHelper()->IsInFolderView());
  500. EXPECT_FALSE(GetAppListTestHelper()->GetBubbleFolderView()->GetVisible());
  501. // The dragged item is now in the top level item list and the reordering is
  502. // recorded.
  503. AppListItemList* item_list = app_list_test_model_->top_level_item_list();
  504. EXPECT_EQ(2u, item_list->item_count());
  505. EXPECT_EQ(item_list->item_at(1)->id(), item_id);
  506. EXPECT_EQ(2u, folder_item->item_list()->item_count());
  507. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  508. kMoveByDragOutOfFolder, 1);
  509. }
  510. TEST_F(ScrollableAppsGridViewTest,
  511. DragItemFromOneFolderToAnotherRecordsHistogram) {
  512. base::HistogramTester histogram_tester;
  513. // Create two folders.
  514. AppListFolderItem* folder_item_1 = CreateAndPopulateFolderWithApps(3);
  515. AppListFolderItem* folder_item_2 = CreateAndPopulateFolderWithApps(2);
  516. ShowAppList();
  517. // Enter the view of the first folder.
  518. LeftClickOn(apps_grid_view_->GetItemViewAt(0));
  519. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  520. // Drag the first app in the folder and move it out of the folder.
  521. StartDragOnItemInFolderAt(0);
  522. DragItemOutOfFolder();
  523. // Move the app item into the other folder and end the drag.
  524. auto* generator = GetEventGenerator();
  525. generator->MoveMouseTo(
  526. apps_grid_view_->GetItemViewAt(1)->GetBoundsInScreen().CenterPoint());
  527. generator->ReleaseLeftButton();
  528. // No folder view is showing now.
  529. EXPECT_FALSE(GetAppListTestHelper()->IsInFolderView());
  530. EXPECT_FALSE(GetAppListTestHelper()->GetBubbleFolderView()->GetVisible());
  531. // The dragged item was moved to another folder and the reordering is
  532. // recorded.
  533. EXPECT_EQ(2u, folder_item_1->item_list()->item_count());
  534. EXPECT_EQ(3u, folder_item_2->item_list()->item_count());
  535. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  536. kMoveIntoAnotherFolder, 1);
  537. }
  538. TEST_F(ScrollableAppsGridViewTest, LeftAndRightArrowKeysMoveSelection) {
  539. PopulateApps(2);
  540. ShowAppList();
  541. auto* apps_grid_view = GetScrollableAppsGridView();
  542. AppListItemView* item1 = apps_grid_view->GetItemViewAt(0);
  543. AppListItemView* item2 = apps_grid_view->GetItemViewAt(1);
  544. apps_grid_view->GetFocusManager()->SetFocusedView(item1);
  545. EXPECT_TRUE(item1->HasFocus());
  546. PressAndReleaseKey(ui::VKEY_RIGHT);
  547. EXPECT_FALSE(item1->HasFocus());
  548. EXPECT_TRUE(item2->HasFocus());
  549. PressAndReleaseKey(ui::VKEY_LEFT);
  550. EXPECT_TRUE(item1->HasFocus());
  551. EXPECT_FALSE(item2->HasFocus());
  552. }
  553. TEST_F(ScrollableAppsGridViewTest, ArrowKeysCanMoveFocusOutOfGrid) {
  554. PopulateApps(2);
  555. ShowAppList();
  556. auto* apps_grid_view = GetScrollableAppsGridView();
  557. AppListItemView* item1 = apps_grid_view->GetItemViewAt(0);
  558. AppListItemView* item2 = apps_grid_view->GetItemViewAt(1);
  559. // Moving left from the first item removes focus from the grid.
  560. apps_grid_view->GetFocusManager()->SetFocusedView(item1);
  561. PressAndReleaseKey(ui::VKEY_LEFT);
  562. EXPECT_FALSE(item1->HasFocus());
  563. EXPECT_FALSE(item2->HasFocus());
  564. // Moving up from the first item removes focus from the grid.
  565. apps_grid_view->GetFocusManager()->SetFocusedView(item1);
  566. PressAndReleaseKey(ui::VKEY_UP);
  567. EXPECT_FALSE(item1->HasFocus());
  568. EXPECT_FALSE(item2->HasFocus());
  569. // Moving right from the last item removes focus from the grid.
  570. apps_grid_view->GetFocusManager()->SetFocusedView(item2);
  571. PressAndReleaseKey(ui::VKEY_RIGHT);
  572. EXPECT_FALSE(item1->HasFocus());
  573. EXPECT_FALSE(item2->HasFocus());
  574. // Moving down from the last item removes focus from the grid.
  575. apps_grid_view->GetFocusManager()->SetFocusedView(item2);
  576. PressAndReleaseKey(ui::VKEY_DOWN);
  577. EXPECT_FALSE(item1->HasFocus());
  578. EXPECT_FALSE(item2->HasFocus());
  579. }
  580. // Tests that histograms are recorded when apps are moved with control+arrow.
  581. TEST_F(ScrollableAppsGridViewTest, ControlArrowRecordsHistogramBasic) {
  582. base::HistogramTester histogram_tester;
  583. PopulateApps(20);
  584. ShowAppList();
  585. ScrollableAppsGridView* apps_grid_view = GetScrollableAppsGridView();
  586. AppListItemView* moving_item = apps_grid_view->GetItemViewAt(0);
  587. apps_grid_view->GetFocusManager()->SetFocusedView(moving_item);
  588. // Make one move right and expect a histogram is recorded.
  589. SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
  590. SimulateKeyReleased(ui::VKEY_RIGHT, ui::EF_NONE);
  591. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  592. kReorderByKeyboardInTopLevel, 1);
  593. // Make one move down and expect a histogram is recorded.
  594. SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN);
  595. SimulateKeyReleased(ui::VKEY_DOWN, ui::EF_NONE);
  596. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  597. kReorderByKeyboardInTopLevel, 2);
  598. // Make one move up and expect a histogram is recorded.
  599. SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN);
  600. SimulateKeyReleased(ui::VKEY_UP, ui::EF_NONE);
  601. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  602. kReorderByKeyboardInTopLevel, 3);
  603. // Make one move left and expect a histogram is recorded.
  604. SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
  605. SimulateKeyReleased(ui::VKEY_LEFT, ui::EF_NONE);
  606. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  607. kReorderByKeyboardInTopLevel, 4);
  608. }
  609. // Test that histograms do not record when the keyboard move is a no-op.
  610. TEST_F(ScrollableAppsGridViewTest,
  611. ControlArrowDoesNotRecordHistogramWithNoOpMove) {
  612. base::HistogramTester histogram_tester;
  613. PopulateApps(20);
  614. ShowAppList();
  615. ScrollableAppsGridView* apps_grid_view = GetScrollableAppsGridView();
  616. AppListItemView* moving_item = apps_grid_view->GetItemViewAt(0);
  617. apps_grid_view->GetFocusManager()->SetFocusedView(moving_item);
  618. // Make 2 no-op moves and one successful move from 0,0 and expect a histogram
  619. // is recorded only once.
  620. SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
  621. SimulateKeyReleased(ui::VKEY_LEFT, ui::EF_NONE);
  622. SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN);
  623. SimulateKeyReleased(ui::VKEY_UP, ui::EF_NONE);
  624. SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
  625. SimulateKeyReleased(ui::VKEY_RIGHT, ui::EF_NONE);
  626. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  627. kReorderByKeyboardInTopLevel, 1);
  628. }
  629. // Tests that histograms are recorded in folder view when apps are moved with
  630. // control+arrow.
  631. TEST_F(ScrollableAppsGridViewTest, ControlArrowRecordsHistogramInFolderBasic) {
  632. base::HistogramTester histogram_tester;
  633. CreateAndPopulateFolderWithApps(4);
  634. ShowAppList();
  635. ScrollableAppsGridView* apps_grid_view = GetScrollableAppsGridView();
  636. // Select the folder item in the grid.
  637. AppListItemView* folder_item_view = apps_grid_view->GetItemViewAt(0);
  638. EXPECT_TRUE(folder_item_view->item()->is_folder());
  639. // Enter the folder view.
  640. apps_grid_view->GetFocusManager()->SetFocusedView(folder_item_view);
  641. SimulateKeyPress(ui::VKEY_RETURN);
  642. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  643. // If the folder view is entered by pressing return key while the focus is on
  644. // the folder, the focus will move to the first item inside the folder view.
  645. AppsGridView* folder_grid_view =
  646. GetAppListTestHelper()->GetBubbleFolderView()->items_grid_view();
  647. EXPECT_EQ(apps_grid_view->GetFocusManager()->GetFocusedView(),
  648. folder_grid_view->GetItemViewAt(0));
  649. // Make one move right and expect a histogram is recorded.
  650. SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
  651. SimulateKeyReleased(ui::VKEY_RIGHT, ui::EF_NONE);
  652. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  653. kReorderByKeyboardInFolder, 1);
  654. // Make one move down and expect a histogram is recorded.
  655. SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN);
  656. SimulateKeyReleased(ui::VKEY_DOWN, ui::EF_NONE);
  657. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  658. kReorderByKeyboardInFolder, 2);
  659. // Make one move left and expect a histogram is recorded.
  660. SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
  661. SimulateKeyReleased(ui::VKEY_LEFT, ui::EF_NONE);
  662. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  663. kReorderByKeyboardInFolder, 3);
  664. // Make one move up and expect a histogram is recorded.
  665. SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN);
  666. SimulateKeyReleased(ui::VKEY_UP, ui::EF_NONE);
  667. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  668. kReorderByKeyboardInFolder, 4);
  669. }
  670. // Tests that histograms do not record when the keyboard move is a no-op in the
  671. // folder view.
  672. TEST_F(ScrollableAppsGridViewTest,
  673. ControlArrowDoesNotRecordHistogramWithNoOpMoveInFolder) {
  674. base::HistogramTester histogram_tester;
  675. CreateAndPopulateFolderWithApps(4);
  676. ShowAppList();
  677. ScrollableAppsGridView* apps_grid_view = GetScrollableAppsGridView();
  678. // Select the folder item in the grid.
  679. AppListItemView* folder_item_view = apps_grid_view->GetItemViewAt(0);
  680. EXPECT_TRUE(folder_item_view->item()->is_folder());
  681. // Enter the folder view.
  682. apps_grid_view->GetFocusManager()->SetFocusedView(folder_item_view);
  683. SimulateKeyPress(ui::VKEY_RETURN);
  684. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  685. // If the folder view is entered by pressing return key while the focus is on
  686. // the folder, the focus will move to the first item inside the folder view.
  687. AppsGridView* folder_grid_view =
  688. GetAppListTestHelper()->GetBubbleFolderView()->items_grid_view();
  689. EXPECT_EQ(apps_grid_view->GetFocusManager()->GetFocusedView(),
  690. folder_grid_view->GetItemViewAt(0));
  691. // Make 2 no-op moves and one successful move from 0,0 and expect a histogram
  692. // is recorded only once.
  693. SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
  694. SimulateKeyReleased(ui::VKEY_LEFT, ui::EF_NONE);
  695. SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN);
  696. SimulateKeyReleased(ui::VKEY_UP, ui::EF_NONE);
  697. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  698. kReorderByKeyboardInFolder, 0);
  699. SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
  700. SimulateKeyReleased(ui::VKEY_RIGHT, ui::EF_NONE);
  701. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  702. kReorderByKeyboardInFolder, 1);
  703. }
  704. // Tests that control + shift + arrow moves selected item out of a folder.
  705. TEST_F(ScrollableAppsGridViewTest, ControlShiftArrowMovesItemOutOfFolder) {
  706. base::HistogramTester histogram_tester;
  707. AppListFolderItem* folder_item = CreateAndPopulateFolderWithApps(5);
  708. ShowAppList();
  709. ScrollableAppsGridView* apps_grid_view = GetScrollableAppsGridView();
  710. // Select the folder item in the grid.
  711. AppListItemView* folder_item_view = apps_grid_view->GetItemViewAt(0);
  712. EXPECT_TRUE(folder_item_view->item()->is_folder());
  713. // Enter the folder view and move the item out of and to the left of the
  714. // folder.
  715. apps_grid_view->GetFocusManager()->SetFocusedView(folder_item_view);
  716. SimulateKeyPress(ui::VKEY_RETURN);
  717. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  718. SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
  719. EXPECT_EQ(apps_grid_view->selected_view(), apps_grid_view->GetItemViewAt(0));
  720. EXPECT_EQ(4u, folder_item->ChildItemCount());
  721. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  722. kMoveByKeyboardOutOfFolder, 1);
  723. // Enter the folder view and move the item out of and to the right of the
  724. // folder.
  725. apps_grid_view->GetFocusManager()->SetFocusedView(folder_item_view);
  726. SimulateKeyPress(ui::VKEY_RETURN);
  727. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  728. SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
  729. EXPECT_EQ(apps_grid_view->selected_view(), apps_grid_view->GetItemViewAt(2));
  730. EXPECT_EQ(3u, folder_item->ChildItemCount());
  731. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  732. kMoveByKeyboardOutOfFolder, 2);
  733. // Enter the folder view and move the item out of and to the above of the
  734. // folder.
  735. apps_grid_view->GetFocusManager()->SetFocusedView(folder_item_view);
  736. SimulateKeyPress(ui::VKEY_RETURN);
  737. SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
  738. EXPECT_EQ(apps_grid_view->selected_view(), apps_grid_view->GetItemViewAt(1));
  739. EXPECT_EQ(2u, folder_item->ChildItemCount());
  740. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  741. kMoveByKeyboardOutOfFolder, 3);
  742. // Enter the folder view and move the item out of and to the below of the
  743. // folder.
  744. apps_grid_view->GetFocusManager()->SetFocusedView(folder_item_view);
  745. SimulateKeyPress(ui::VKEY_RETURN);
  746. ASSERT_TRUE(GetAppListTestHelper()->IsInFolderView());
  747. SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
  748. EXPECT_EQ(apps_grid_view->selected_view(), apps_grid_view->GetItemViewAt(3));
  749. histogram_tester.ExpectBucketCount("Apps.AppListBubbleAppMovingType",
  750. kMoveByKeyboardOutOfFolder, 4);
  751. EXPECT_FALSE(GetAppListTestHelper()->IsInFolderView());
  752. }
  753. // Verify on the apps grid with zero scroll offset.
  754. TEST_F(ScrollableAppsGridViewTest, VerifyVisibleRangeByDefault) {
  755. PopulateApps(33);
  756. ShowAppList();
  757. const int cols = apps_grid_view_->cols();
  758. // Assume that the column count is 5 so choose a number that is not the
  759. // multiple of 5 as the total item count.
  760. ASSERT_EQ(5, cols);
  761. // Verify that the items on row 0 to row 3 are visible at default.
  762. EXPECT_TRUE(
  763. IsIndexRangeExpected(/*first_index=*/0, /*last_index=*/4 * cols - 1));
  764. }
  765. // Verify on the apps grid whose first row is unfilled.
  766. TEST_F(ScrollableAppsGridViewTest, VerifyVisibleRangeFirstRowUnfilled) {
  767. PopulateApps(4);
  768. ShowAppList();
  769. const int cols = apps_grid_view_->cols();
  770. // Assume that the column count is 5 so choose a smaller number as the total
  771. // item count.
  772. ASSERT_EQ(5, cols);
  773. // Verify that the items on the first row are visible at default.
  774. EXPECT_TRUE(IsIndexRangeExpected(/*first_index=*/0, /*last_index=*/3));
  775. }
  776. // Verify on the apps grid whose first row is filled.
  777. TEST_F(ScrollableAppsGridViewTest, VerifyVisibleRangeFirstRowFilled) {
  778. PopulateApps(5);
  779. ShowAppList();
  780. const int cols = apps_grid_view_->cols();
  781. // Assume that the column count is 5 so apps just fill the first row.
  782. ASSERT_EQ(5, cols);
  783. // Verify that the items on the first row are visible at default.
  784. EXPECT_TRUE(IsIndexRangeExpected(/*first_index=*/0, /*last_index=*/4));
  785. }
  786. // Verify on the apps grid with a non-zero scroll offset.
  787. TEST_F(ScrollableAppsGridViewTest, VerifyVisibleRangeAfterScrolling) {
  788. PopulateApps(33);
  789. ShowAppList();
  790. const int cols = apps_grid_view_->cols();
  791. // Assume that the column count is 5 so choose a number that is not the
  792. // multiple of 5 as the total item count.
  793. ASSERT_EQ(5, cols);
  794. // Scroll the apps grid so that the item views on the first row are hidden.
  795. // To calculate the scroll offset, the origin of the item view at (row 1,
  796. // column 0) should be translated into the scroll content's coordinates.
  797. views::View* item_view = apps_grid_view_->GetItemViewAt(5);
  798. views::ScrollView* scroll_view = apps_grid_view_->scroll_view_for_test();
  799. gfx::Point local_origin;
  800. views::View::ConvertPointToTarget(item_view, scroll_view->contents(),
  801. &local_origin);
  802. const int offset = local_origin.y() - scroll_view->GetVisibleRect().y();
  803. scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(), offset);
  804. // Verify that in this case the items on row 1 to row 5 are visible.
  805. EXPECT_TRUE(
  806. IsIndexRangeExpected(/*first_index=*/cols, /*last_index=*/6 * cols - 1));
  807. }
  808. // Verify visible items' index range by scrolling to the end on a partially
  809. // filled apps grid.
  810. TEST_F(ScrollableAppsGridViewTest,
  811. VerifyVisibleRangeAfterScrollingToEndPartiallyFilled) {
  812. constexpr int populated_app_count = 33;
  813. PopulateApps(populated_app_count);
  814. ShowAppList();
  815. const int cols = apps_grid_view_->cols();
  816. // Assume that the column count is 5 so choose a number that is not the
  817. // multiple of 5 as the total item count.
  818. ASSERT_EQ(5, cols);
  819. // Scroll to the end.
  820. scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(),
  821. std::numeric_limits<int>::max());
  822. // Verify that the items on row 3 to row 6 are visible.
  823. EXPECT_TRUE(IsIndexRangeExpected(/*first_index=*/3 * cols,
  824. /*last_index=*/populated_app_count - 1));
  825. }
  826. // Verify visible items' item index range by scrolling to the end on a full
  827. // apps grid.
  828. TEST_F(ScrollableAppsGridViewTest,
  829. VerifyVisibleRangeAfterScrollingToEndFilled) {
  830. constexpr int populated_app_count = 35;
  831. PopulateApps(populated_app_count);
  832. ShowAppList();
  833. const int cols = apps_grid_view_->cols();
  834. // Assume that the column count is 5 so choose a column count's multiple as
  835. // the total item count.
  836. ASSERT_EQ(5, cols);
  837. // Scroll to the end.
  838. scroll_view_->ScrollToPosition(scroll_view_->vertical_scroll_bar(),
  839. std::numeric_limits<int>::max());
  840. // Verify that the items on row 3 to row 6 are visible.
  841. EXPECT_TRUE(IsIndexRangeExpected(/*first_index=*/3 * cols,
  842. /*last_index=*/populated_app_count - 1));
  843. }
  844. // Tests the scrollable apps grid view with app list nudge enabled.
  845. class ScrollableAppsGridViewWithNudgeTest : public ScrollableAppsGridViewTest {
  846. public:
  847. // ScrollableAppsGridViewTest:
  848. void SetUp() override {
  849. ScrollableAppsGridViewTest::SetUp();
  850. GetAppListTestHelper()->DisableAppListNudge(false);
  851. }
  852. };
  853. // Verify on the apps grid with zero scroll offset.
  854. TEST_F(ScrollableAppsGridViewWithNudgeTest, VerifyVisibleRangeByDefault) {
  855. PopulateApps(33);
  856. ShowAppList();
  857. const int cols = apps_grid_view_->cols();
  858. // Assume that the column count is 5 so choose a number that is not the
  859. // multiple of 5 as the total item count.
  860. ASSERT_EQ(5, cols);
  861. // With the app list reorder nudge is showing, there's enough space to fit
  862. // only 4 rows of apps in the visible portion of the app list.
  863. EXPECT_TRUE(
  864. IsIndexRangeExpected(/*first_index=*/0, /*last_index=*/4 * cols - 1));
  865. }
  866. } // namespace ash