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