Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / apps_grid_view_unittest.cc
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 "ui/app_list/views/apps_grid_view.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/app_list/app_list_constants.h"
18 #include "ui/app_list/app_list_folder_item.h"
19 #include "ui/app_list/app_list_item.h"
20 #include "ui/app_list/app_list_model.h"
21 #include "ui/app_list/app_list_switches.h"
22 #include "ui/app_list/pagination_model.h"
23 #include "ui/app_list/test/app_list_test_model.h"
24 #include "ui/app_list/views/app_list_item_view.h"
25 #include "ui/app_list/views/apps_grid_view_folder_delegate.h"
26 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
27 #include "ui/views/test/views_test_base.h"
28
29 namespace app_list {
30 namespace test {
31
32 namespace {
33
34 const int kCols = 2;
35 const int kRows = 2;
36 const int kTilesPerPage = kCols * kRows;
37
38 const int kWidth = 320;
39 const int kHeight = 240;
40
41 class PageFlipWaiter : public PaginationModelObserver {
42  public:
43   PageFlipWaiter(base::MessageLoopForUI* ui_loop, PaginationModel* model)
44       : ui_loop_(ui_loop), model_(model), wait_(false) {
45     model_->AddObserver(this);
46   }
47
48   virtual ~PageFlipWaiter() {
49     model_->RemoveObserver(this);
50   }
51
52   void Wait() {
53     DCHECK(!wait_);
54     wait_ = true;
55
56     ui_loop_->Run();
57     wait_ = false;
58   }
59
60   void Reset() { selected_pages_.clear(); }
61
62   const std::string& selected_pages() const { return selected_pages_; }
63
64  private:
65   // PaginationModelObserver overrides:
66   virtual void TotalPagesChanged() OVERRIDE {
67   }
68   virtual void SelectedPageChanged(int old_selected,
69                                    int new_selected) OVERRIDE {
70     if (!selected_pages_.empty())
71       selected_pages_ += ',';
72     selected_pages_ += base::IntToString(new_selected);
73
74     if (wait_)
75       ui_loop_->Quit();
76   }
77   virtual void TransitionStarted() OVERRIDE {
78   }
79   virtual void TransitionChanged() OVERRIDE {
80   }
81
82   base::MessageLoopForUI* ui_loop_;
83   PaginationModel* model_;
84   bool wait_;
85   std::string selected_pages_;
86
87   DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter);
88 };
89
90 }  // namespace
91
92 class AppsGridViewTest : public views::ViewsTestBase {
93  public:
94   AppsGridViewTest() {}
95   virtual ~AppsGridViewTest() {}
96
97   // testing::Test overrides:
98   virtual void SetUp() OVERRIDE {
99     views::ViewsTestBase::SetUp();
100     model_.reset(new AppListTestModel);
101     model_->SetFoldersEnabled(true);
102
103     apps_grid_view_.reset(new AppsGridView(NULL));
104     apps_grid_view_->SetLayout(kCols, kRows);
105     apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight)));
106     apps_grid_view_->SetModel(model_.get());
107     apps_grid_view_->SetItemList(model_->top_level_item_list());
108
109     test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
110   }
111   virtual void TearDown() OVERRIDE {
112     apps_grid_view_.reset();  // Release apps grid view before models.
113     views::ViewsTestBase::TearDown();
114   }
115
116  protected:
117   void EnsureFoldersEnabled() {
118     // Folders require AppList sync to be enabled.
119     CommandLine::ForCurrentProcess()->AppendSwitch(
120         switches::kEnableSyncAppList);
121   }
122
123   AppListItemView* GetItemViewAt(int index) {
124     return static_cast<AppListItemView*>(
125         test_api_->GetViewAtModelIndex(index));
126   }
127
128   AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
129     for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) {
130       AppListItemView* view = GetItemViewAt(i);
131       if (view->bounds().Contains(point))
132         return view;
133     }
134     return NULL;
135   }
136
137   gfx::Rect GetItemTileRectAt(int row, int col) {
138     DCHECK_GT(model_->top_level_item_list()->item_count(), 0u);
139
140     gfx::Insets insets(apps_grid_view_->GetInsets());
141     gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
142                    GetItemViewAt(0)->bounds().size());
143     rect.Offset(col * rect.width(), row * rect.height());
144     return rect;
145   }
146
147   PaginationModel* GetPaginationModel() {
148     return apps_grid_view_->pagination_model();
149   }
150
151   // Points are in |apps_grid_view_|'s coordinates.
152   void SimulateDrag(AppsGridView::Pointer pointer,
153                     const gfx::Point& from,
154                     const gfx::Point& to) {
155     AppListItemView* view = GetItemViewForPoint(from);
156     DCHECK(view);
157
158     gfx::Point translated_from = gfx::PointAtOffsetFromOrigin(
159         from - view->bounds().origin());
160     gfx::Point translated_to = gfx::PointAtOffsetFromOrigin(
161         to - view->bounds().origin());
162
163     ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED,
164                                  translated_from, from, 0, 0);
165     apps_grid_view_->InitiateDrag(view, pointer, pressed_event);
166
167     ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
168                               translated_to, to, 0, 0);
169     apps_grid_view_->UpdateDragFromItem(pointer, drag_event);
170   }
171
172   void SimulateKeyPress(ui::KeyboardCode key_code) {
173     ui::KeyEvent key_event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
174     apps_grid_view_->OnKeyPressed(key_event);
175   }
176
177   scoped_ptr<AppListTestModel> model_;
178   scoped_ptr<AppsGridView> apps_grid_view_;
179   scoped_ptr<AppsGridViewTestApi> test_api_;
180
181  private:
182   DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
183 };
184
185 class TestAppsGridViewFolderDelegate : public AppsGridViewFolderDelegate {
186  public:
187   TestAppsGridViewFolderDelegate() : show_bubble_(false) {}
188   virtual ~TestAppsGridViewFolderDelegate() {}
189
190   // Overridden from AppsGridViewFolderDelegate:
191   virtual void UpdateFolderViewBackground(bool show_bubble) OVERRIDE {
192     show_bubble_ = show_bubble;
193   }
194
195   virtual void ReparentItem(AppListItemView* original_drag_view,
196                             const gfx::Point& drag_point_in_folder_grid)
197       OVERRIDE {}
198
199   virtual void DispatchDragEventForReparent(
200       AppsGridView::Pointer pointer,
201       const gfx::Point& drag_point_in_folder_grid) OVERRIDE {}
202
203   virtual void DispatchEndDragEventForReparent(
204       bool events_forwarded_to_drag_drop_host,
205       bool cancel_drag) OVERRIDE {}
206
207   virtual bool IsPointOutsideOfFolderBoundary(const gfx::Point& point)
208       OVERRIDE {
209     return false;
210   }
211
212   virtual bool IsOEMFolder() const OVERRIDE { return false; }
213
214   virtual void SetRootLevelDragViewVisible(bool visible) OVERRIDE {}
215
216   bool show_bubble() { return show_bubble_; }
217
218  private:
219   bool show_bubble_;
220
221   DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate);
222 };
223
224 TEST_F(AppsGridViewTest, CreatePage) {
225   // Fully populates a page.
226   const int kPages = 1;
227   model_->PopulateApps(kPages * kTilesPerPage);
228   EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
229
230   // Adds one more and gets a new page created.
231   model_->CreateAndAddItem("Extra");
232   EXPECT_EQ(kPages + 1, GetPaginationModel()->total_pages());
233 }
234
235 TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
236   const int kPages = 3;
237   model_->PopulateApps(kPages * kTilesPerPage);
238   EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
239   EXPECT_EQ(0, GetPaginationModel()->selected_page());
240
241   // Highlight first one and last one one first page and first page should be
242   // selected.
243   model_->HighlightItemAt(0);
244   EXPECT_EQ(0, GetPaginationModel()->selected_page());
245   model_->HighlightItemAt(kTilesPerPage - 1);
246   EXPECT_EQ(0, GetPaginationModel()->selected_page());
247
248   // Highlight first one on 2nd page and 2nd page should be selected.
249   model_->HighlightItemAt(kTilesPerPage + 1);
250   EXPECT_EQ(1, GetPaginationModel()->selected_page());
251
252   // Highlight last one in the model and last page should be selected.
253   model_->HighlightItemAt(model_->top_level_item_list()->item_count() - 1);
254   EXPECT_EQ(kPages - 1, GetPaginationModel()->selected_page());
255 }
256
257 TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
258   const int kTotalItems = 2;
259   const int kLastItemIndex = kTotalItems - 1;
260
261   model_->PopulateApps(kTotalItems);
262
263   AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
264   apps_grid_view_->SetSelectedView(last_view);
265   model_->DeleteItem(model_->GetItemName(kLastItemIndex));
266
267   EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
268
269   // No crash happens.
270   AppListItemView* view = GetItemViewAt(0);
271   apps_grid_view_->SetSelectedView(view);
272   EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
273 }
274
275 TEST_F(AppsGridViewTest, MouseDragWithFolderDisabled) {
276   model_->SetFoldersEnabled(false);
277   const int kTotalItems = 4;
278   model_->PopulateApps(kTotalItems);
279   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
280             model_->GetModelContent());
281
282   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
283   gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
284
285   // Dragging changes model order.
286   SimulateDrag(AppsGridView::MOUSE, from, to);
287   apps_grid_view_->EndDrag(false);
288   EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
289             model_->GetModelContent());
290   test_api_->LayoutToIdealBounds();
291
292   // Canceling drag should keep existing order.
293   SimulateDrag(AppsGridView::MOUSE, from, to);
294   apps_grid_view_->EndDrag(true);
295   EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
296             model_->GetModelContent());
297   test_api_->LayoutToIdealBounds();
298
299   // Deleting an item keeps remaining intact.
300   SimulateDrag(AppsGridView::MOUSE, from, to);
301   model_->DeleteItem(model_->GetItemName(0));
302   apps_grid_view_->EndDrag(false);
303   EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
304             model_->GetModelContent());
305   test_api_->LayoutToIdealBounds();
306
307   // Adding a launcher item cancels the drag and respects the order.
308   SimulateDrag(AppsGridView::MOUSE, from, to);
309   EXPECT_TRUE(apps_grid_view_->has_dragged_view());
310   model_->CreateAndAddItem("Extra");
311   // No need to EndDrag explicitly - adding an item should do this.
312   EXPECT_FALSE(apps_grid_view_->has_dragged_view());
313   // Even though cancelled, mouse move events can still arrive via the item
314   // view. Ensure that behaves sanely, and doesn't start a new drag.
315   ui::MouseEvent drag_event(
316       ui::ET_MOUSE_DRAGGED, gfx::Point(1, 1), gfx::Point(2, 2), 0, 0);
317   apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event);
318   EXPECT_FALSE(apps_grid_view_->has_dragged_view());
319
320   EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
321             model_->GetModelContent());
322   test_api_->LayoutToIdealBounds();
323 }
324
325 TEST_F(AppsGridViewTest, MouseDragItemIntoFolder) {
326   EnsureFoldersEnabled();
327
328   size_t kTotalItems = 3;
329   model_->PopulateApps(kTotalItems);
330   EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
331   EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_->GetModelContent());
332
333   gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
334   gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
335
336   // Dragging item_1 over item_0 creates a folder.
337   SimulateDrag(AppsGridView::MOUSE, from, to);
338   apps_grid_view_->EndDrag(false);
339   EXPECT_EQ(kTotalItems - 1, model_->top_level_item_list()->item_count());
340   EXPECT_EQ(AppListFolderItem::kItemType,
341             model_->top_level_item_list()->item_at(0)->GetItemType());
342   AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
343       model_->top_level_item_list()->item_at(0));
344   EXPECT_EQ(2u, folder_item->ChildItemCount());
345   AppListItem* item_0 = model_->FindItem("Item 0");
346   EXPECT_TRUE(item_0->IsInFolder());
347   EXPECT_EQ(folder_item->id(), item_0->folder_id());
348   AppListItem* item_1 = model_->FindItem("Item 1");
349   EXPECT_TRUE(item_1->IsInFolder());
350   EXPECT_EQ(folder_item->id(), item_1->folder_id());
351   std::string expected_items = folder_item->id() + ",Item 2";
352   EXPECT_EQ(expected_items, model_->GetModelContent());
353   test_api_->LayoutToIdealBounds();
354
355   // Dragging item_2 to the folder adds item_2 to the folder.
356   SimulateDrag(AppsGridView::MOUSE, from, to);
357   apps_grid_view_->EndDrag(false);
358
359   EXPECT_EQ(kTotalItems - 2, model_->top_level_item_list()->item_count());
360   EXPECT_EQ(folder_item->id(), model_->GetModelContent());
361   EXPECT_EQ(3u, folder_item->ChildItemCount());
362   item_0 = model_->FindItem("Item 0");
363   EXPECT_TRUE(item_0->IsInFolder());
364   EXPECT_EQ(folder_item->id(), item_0->folder_id());
365   item_1 = model_->FindItem("Item 1");
366   EXPECT_TRUE(item_1->IsInFolder());
367   EXPECT_EQ(folder_item->id(), item_1->folder_id());
368   AppListItem* item_2 = model_->FindItem("Item 2");
369   EXPECT_TRUE(item_2->IsInFolder());
370   EXPECT_EQ(folder_item->id(), item_2->folder_id());
371   test_api_->LayoutToIdealBounds();
372 }
373
374 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolder) {
375   EnsureFoldersEnabled();
376
377   // Create and add a folder with 15 items in it.
378   size_t kTotalItems = kMaxFolderItems - 1;
379   model_->CreateAndPopulateFolderWithApps(kTotalItems);
380   EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
381   EXPECT_EQ(AppListFolderItem::kItemType,
382             model_->top_level_item_list()->item_at(0)->GetItemType());
383   AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
384       model_->top_level_item_list()->item_at(0));
385   EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
386
387   // Create and add another 2 items.
388   model_->PopulateAppWithId(kTotalItems);
389   model_->PopulateAppWithId(kTotalItems + 1);
390   EXPECT_EQ(3u, model_->top_level_item_list()->item_count());
391   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
392   EXPECT_EQ(model_->GetItemName(kMaxFolderItems - 1),
393             model_->top_level_item_list()->item_at(1)->id());
394   EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
395             model_->top_level_item_list()->item_at(2)->id());
396
397   gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
398   gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
399
400   // Dragging one item into the folder, the folder should accept the item.
401   SimulateDrag(AppsGridView::MOUSE, from, to);
402   apps_grid_view_->EndDrag(false);
403   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
404   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
405   EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
406   EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
407             model_->top_level_item_list()->item_at(1)->id());
408   test_api_->LayoutToIdealBounds();
409
410   // Dragging the last item over the folder, the folder won't accept the new
411   // item, instead, it will re-order the items.
412   SimulateDrag(AppsGridView::MOUSE, from, to);
413   apps_grid_view_->EndDrag(false);
414   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
415   EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
416             model_->top_level_item_list()->item_at(0)->id());
417   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
418   EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
419   test_api_->LayoutToIdealBounds();
420 }
421
422 TEST_F(AppsGridViewTest, MouseDragItemReorder) {
423   // This test assumes Folders are enabled.
424   EnsureFoldersEnabled();
425
426   size_t kTotalItems = 2;
427   model_->PopulateApps(kTotalItems);
428   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
429   EXPECT_EQ(std::string("Item 0,Item 1"), model_->GetModelContent());
430
431   gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
432   int reorder_offset = (GetItemTileRectAt(0, 1).CenterPoint() -
433                         GetItemTileRectAt(0, 0).CenterPoint()).Length() -
434                        kReorderDroppingCircleRadius - kGridIconDimension / 2 +
435                        5;
436   gfx::Point to = gfx::Point(from.x() - reorder_offset, from.y());
437
438   // Dragging item_1 closing to item_0 should leads to re-ordering these two
439   // items.
440   SimulateDrag(AppsGridView::MOUSE, from, to);
441   apps_grid_view_->EndDrag(false);
442   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
443   EXPECT_EQ(std::string("Item 1,Item 0"), model_->GetModelContent());
444   test_api_->LayoutToIdealBounds();
445 }
446
447 TEST_F(AppsGridViewTest, MouseDragFolderReorder) {
448   EnsureFoldersEnabled();
449
450   size_t kTotalItems = 2;
451   model_->CreateAndPopulateFolderWithApps(kTotalItems);
452   model_->PopulateAppWithId(kTotalItems);
453   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
454   EXPECT_EQ(AppListFolderItem::kItemType,
455             model_->top_level_item_list()->item_at(0)->GetItemType());
456   AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
457       model_->top_level_item_list()->item_at(0));
458   EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(1)->id());
459
460   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
461   gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
462
463   // Dragging folder over item_1 should leads to re-ordering these two
464   // items.
465   SimulateDrag(AppsGridView::MOUSE, from, to);
466   apps_grid_view_->EndDrag(false);
467   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
468   EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(0)->id());
469   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
470   test_api_->LayoutToIdealBounds();
471 }
472
473 TEST_F(AppsGridViewTest, MouseDragWithCancelDeleteAddItem) {
474   size_t kTotalItems = 4;
475   model_->PopulateApps(kTotalItems);
476   EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
477   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
478             model_->GetModelContent());
479
480   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
481   gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
482
483   // Canceling drag should keep existing order.
484   SimulateDrag(AppsGridView::MOUSE, from, to);
485   apps_grid_view_->EndDrag(true);
486   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
487             model_->GetModelContent());
488   test_api_->LayoutToIdealBounds();
489
490   // Deleting an item keeps remaining intact.
491   SimulateDrag(AppsGridView::MOUSE, from, to);
492   model_->DeleteItem(model_->GetItemName(2));
493   apps_grid_view_->EndDrag(false);
494   EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_->GetModelContent());
495   test_api_->LayoutToIdealBounds();
496
497   // Adding a launcher item cancels the drag and respects the order.
498   SimulateDrag(AppsGridView::MOUSE, from, to);
499   model_->CreateAndAddItem("Extra");
500   apps_grid_view_->EndDrag(false);
501   EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
502             model_->GetModelContent());
503   test_api_->LayoutToIdealBounds();
504 }
505
506 TEST_F(AppsGridViewTest, MouseDragFlipPage) {
507   test_api_->SetPageFlipDelay(10);
508   GetPaginationModel()->SetTransitionDurations(10, 10);
509
510   PageFlipWaiter page_flip_waiter(message_loop(), GetPaginationModel());
511
512   const int kPages = 3;
513   model_->PopulateApps(kPages * kTilesPerPage);
514   EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
515   EXPECT_EQ(0, GetPaginationModel()->selected_page());
516
517   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
518   gfx::Point to = gfx::Point(apps_grid_view_->width(),
519                              apps_grid_view_->height() / 2);
520
521   // Drag to right edge.
522   page_flip_waiter.Reset();
523   SimulateDrag(AppsGridView::MOUSE, from, to);
524
525   // Page should be flipped after sometime to hit page 1 and 2 then stop.
526   while (test_api_->HasPendingPageFlip()) {
527     page_flip_waiter.Wait();
528   }
529   EXPECT_EQ("1,2", page_flip_waiter.selected_pages());
530   EXPECT_EQ(2, GetPaginationModel()->selected_page());
531
532   apps_grid_view_->EndDrag(true);
533
534   // Now drag to the left edge and test the other direction.
535   to.set_x(0);
536
537   page_flip_waiter.Reset();
538   SimulateDrag(AppsGridView::MOUSE, from, to);
539
540   while (test_api_->HasPendingPageFlip()) {
541     page_flip_waiter.Wait();
542   }
543   EXPECT_EQ("1,0", page_flip_waiter.selected_pages());
544   EXPECT_EQ(0, GetPaginationModel()->selected_page());
545
546   apps_grid_view_->EndDrag(true);
547 }
548
549 TEST_F(AppsGridViewTest, SimultaneousDragWithFolderDisabled) {
550   model_->SetFoldersEnabled(false);
551   const int kTotalItems = 4;
552   model_->PopulateApps(kTotalItems);
553   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
554             model_->GetModelContent());
555
556   gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
557   gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
558
559   gfx::Point touch_from = GetItemTileRectAt(1, 0).CenterPoint();
560   gfx::Point touch_to = GetItemTileRectAt(1, 1).CenterPoint();
561
562   // Starts a mouse drag first then a touch drag.
563   SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
564   SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
565   // Finishes the drag and mouse drag wins.
566   apps_grid_view_->EndDrag(false);
567   EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
568             model_->GetModelContent());
569   test_api_->LayoutToIdealBounds();
570
571   // Starts a touch drag first then a mouse drag.
572   SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
573   SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
574   // Finishes the drag and touch drag wins.
575   apps_grid_view_->EndDrag(false);
576   EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
577             model_->GetModelContent());
578   test_api_->LayoutToIdealBounds();
579 }
580
581 TEST_F(AppsGridViewTest, UpdateFolderBackgroundOnCancelDrag) {
582   EnsureFoldersEnabled();
583
584   const int kTotalItems = 4;
585   TestAppsGridViewFolderDelegate folder_delegate;
586   apps_grid_view_->set_folder_delegate(&folder_delegate);
587   model_->PopulateApps(kTotalItems);
588   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
589             model_->GetModelContent());
590
591   gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
592   gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
593
594   // Starts a mouse drag and then cancels it.
595   SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
596   EXPECT_TRUE(folder_delegate.show_bubble());
597   apps_grid_view_->EndDrag(true);
598   EXPECT_FALSE(folder_delegate.show_bubble());
599   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
600             model_->GetModelContent());
601 }
602
603 TEST_F(AppsGridViewTest, HighlightWithKeyboard) {
604   const int kPages = 3;
605   const int kItems = (kPages - 1) * kTilesPerPage + 1;
606   model_->PopulateApps(kItems);
607
608   const int first_index = 0;
609   const int last_index = kItems - 1;
610   const int last_index_on_page1_first_row = kRows - 1;
611   const int last_index_on_page1 = kTilesPerPage - 1;
612   const int first_index_on_page2 = kTilesPerPage;
613   const int first_index_on_page2_last_row = 2 * kTilesPerPage - kRows;
614   const int last_index_on_page2_last_row = 2 * kTilesPerPage - 1;
615
616   // Try moving off the item beyond the first one.
617   apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
618   SimulateKeyPress(ui::VKEY_UP);
619   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
620   SimulateKeyPress(ui::VKEY_LEFT);
621   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
622
623   // Move to the last item and try to go past it.
624   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index));
625   SimulateKeyPress(ui::VKEY_DOWN);
626   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
627   SimulateKeyPress(ui::VKEY_RIGHT);
628   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
629
630   // Move right on last item on page 1 should get to first item on page 2's last
631   // row and vice versa.
632   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
633   SimulateKeyPress(ui::VKEY_RIGHT);
634   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
635       first_index_on_page2_last_row)));
636   SimulateKeyPress(ui::VKEY_LEFT);
637   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
638       last_index_on_page1)));
639
640   // Up/down on page boundary does nothing.
641   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
642   SimulateKeyPress(ui::VKEY_DOWN);
643   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
644       last_index_on_page1)));
645   apps_grid_view_->SetSelectedView(
646       GetItemViewAt(first_index_on_page2_last_row));
647   apps_grid_view_->
648       SetSelectedView(GetItemViewAt(last_index_on_page1_first_row));
649   SimulateKeyPress(ui::VKEY_UP);
650   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
651       last_index_on_page1_first_row)));
652
653   // Page up and down should go to the same item on the next and last page.
654   apps_grid_view_->SetSelectedView(GetItemViewAt(first_index_on_page2));
655   SimulateKeyPress(ui::VKEY_PRIOR);
656   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
657       first_index)));
658   SimulateKeyPress(ui::VKEY_NEXT);
659   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
660       first_index_on_page2)));
661
662   // Moving onto a a page with too few apps to support the expected index snaps
663   // to the last available index.
664   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
665   SimulateKeyPress(ui::VKEY_RIGHT);
666   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
667       last_index)));
668   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
669   SimulateKeyPress(ui::VKEY_NEXT);
670   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
671       last_index)));
672
673
674
675   // After page switch, arrow keys select first item on current page.
676   apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
677   GetPaginationModel()->SelectPage(1, false);
678   SimulateKeyPress(ui::VKEY_UP);
679   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
680       first_index_on_page2)));
681 }
682
683 TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
684   // If the app's full name and short name differ, the title label's tooltip
685   // should always be the full name of the app.
686   std::string expected_text("xyz");
687   std::string expected_tooltip("tooltip");
688   AppListItem* item = model_->CreateAndAddItem("Item with short name");
689   model_->SetItemNameAndShortName(item, expected_tooltip, expected_text);
690
691   base::string16 actual_tooltip;
692   AppListItemView* item_view = GetItemViewAt(0);
693   ASSERT_TRUE(item_view);
694   const views::Label* title_label = item_view->title();
695   EXPECT_TRUE(title_label->GetTooltipText(
696       title_label->bounds().CenterPoint(), &actual_tooltip));
697   EXPECT_EQ(expected_tooltip, base::UTF16ToUTF8(actual_tooltip));
698   EXPECT_EQ(expected_text, base::UTF16ToUTF8(title_label->text()));
699 }
700
701 TEST_F(AppsGridViewTest, ItemLabelNoShortName) {
702   // If the app's full name and short name are the same, use the default tooltip
703   // behavior of the label (only show a tooltip if the title is truncated).
704   std::string title("a");
705   AppListItem* item = model_->CreateAndAddItem(title);
706   model_->SetItemNameAndShortName(item, title, "");
707
708   base::string16 actual_tooltip;
709   AppListItemView* item_view = GetItemViewAt(0);
710   ASSERT_TRUE(item_view);
711   const views::Label* title_label = item_view->title();
712   EXPECT_FALSE(title_label->GetTooltipText(
713       title_label->bounds().CenterPoint(), &actual_tooltip));
714   EXPECT_EQ(title, base::UTF16ToUTF8(title_label->text()));
715 }
716
717 }  // namespace test
718 }  // namespace app_list