Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ash / system / tray / system_tray_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 "ash/system/tray/system_tray.h"
6
7 #include <vector>
8
9 #include "ash/accessibility_delegate.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/shelf/shelf_layout_manager.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/system/status_area_widget.h"
15 #include "ash/system/tray/system_tray_bubble.h"
16 #include "ash/system/tray/system_tray_item.h"
17 #include "ash/system/tray/tray_constants.h"
18 #include "ash/system/tray/tray_popup_item_container.h"
19 #include "ash/test/ash_test_base.h"
20 #include "ash/wm/window_util.h"
21 #include "base/command_line.h"
22 #include "base/run_loop.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "ui/aura/window.h"
25 #include "ui/base/ui_base_switches.h"
26 #include "ui/base/ui_base_types.h"
27 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
28 #include "ui/events/test/event_generator.h"
29 #include "ui/gfx/geometry/point.h"
30 #include "ui/gfx/geometry/rect.h"
31 #include "ui/views/controls/label.h"
32 #include "ui/views/layout/fill_layout.h"
33 #include "ui/views/view.h"
34 #include "ui/views/widget/widget.h"
35 #include "ui/views/widget/widget_delegate.h"
36
37 #if defined(OS_WIN)
38 #include "base/win/windows_version.h"
39 #endif
40
41 namespace ash {
42 namespace test {
43
44 namespace {
45
46 SystemTray* GetSystemTray() {
47   return Shell::GetPrimaryRootWindowController()->shelf()->
48       status_area_widget()->system_tray();
49 }
50
51 // Trivial item implementation that tracks its views for testing.
52 class TestItem : public SystemTrayItem {
53  public:
54   TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL) {}
55
56   views::View* CreateTrayView(user::LoginStatus status) override {
57     tray_view_ = new views::View;
58     // Add a label so it has non-zero width.
59     tray_view_->SetLayoutManager(new views::FillLayout);
60     tray_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Tray")));
61     return tray_view_;
62   }
63
64   views::View* CreateDefaultView(user::LoginStatus status) override {
65     default_view_ = new views::View;
66     default_view_->SetLayoutManager(new views::FillLayout);
67     default_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Default")));
68     return default_view_;
69   }
70
71   views::View* CreateDetailedView(user::LoginStatus status) override {
72     detailed_view_ = new views::View;
73     detailed_view_->SetLayoutManager(new views::FillLayout);
74     detailed_view_->AddChildView(
75         new views::Label(base::UTF8ToUTF16("Detailed")));
76     return detailed_view_;
77   }
78
79   views::View* CreateNotificationView(user::LoginStatus status) override {
80     notification_view_ = new views::View;
81     return notification_view_;
82   }
83
84   void DestroyTrayView() override { tray_view_ = NULL; }
85
86   void DestroyDefaultView() override { default_view_ = NULL; }
87
88   void DestroyDetailedView() override { detailed_view_ = NULL; }
89
90   void DestroyNotificationView() override { notification_view_ = NULL; }
91
92   void UpdateAfterLoginStatusChange(user::LoginStatus status) override {}
93
94   views::View* tray_view() const { return tray_view_; }
95   views::View* default_view() const { return default_view_; }
96   views::View* detailed_view() const { return detailed_view_; }
97   views::View* notification_view() const { return notification_view_; }
98
99  private:
100   views::View* tray_view_;
101   views::View* default_view_;
102   views::View* detailed_view_;
103   views::View* notification_view_;
104 };
105
106 // Trivial item implementation that returns NULL from tray/default/detailed
107 // view creation methods.
108 class TestNoViewItem : public SystemTrayItem {
109  public:
110   TestNoViewItem() : SystemTrayItem(GetSystemTray()) {}
111
112   views::View* CreateTrayView(user::LoginStatus status) override {
113     return NULL;
114   }
115
116   views::View* CreateDefaultView(user::LoginStatus status) override {
117     return NULL;
118   }
119
120   views::View* CreateDetailedView(user::LoginStatus status) override {
121     return NULL;
122   }
123
124   views::View* CreateNotificationView(user::LoginStatus status) override {
125     return NULL;
126   }
127
128   void DestroyTrayView() override {}
129   void DestroyDefaultView() override {}
130   void DestroyDetailedView() override {}
131   void DestroyNotificationView() override {}
132   void UpdateAfterLoginStatusChange(user::LoginStatus status) override {}
133 };
134
135 class ModalWidgetDelegate : public views::WidgetDelegateView {
136  public:
137   ModalWidgetDelegate() {}
138   ~ModalWidgetDelegate() override {}
139
140   views::View* GetContentsView() override { return this; }
141   ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_SYSTEM; }
142
143  private:
144   DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
145 };
146
147 }  // namespace
148
149 class SystemTrayTest : public AshTestBase {
150  public:
151   SystemTrayTest() {}
152   ~SystemTrayTest() override {}
153
154   void SetUp() override {
155     base::CommandLine::ForCurrentProcess()->AppendSwitch(
156         switches::kEnableTouchFeedback);
157     test::AshTestBase::SetUp();
158   }
159
160  private:
161   DISALLOW_COPY_AND_ASSIGN(SystemTrayTest);
162 };
163
164 TEST_F(SystemTrayTest, SystemTrayDefaultView) {
165   SystemTray* tray = GetSystemTray();
166   ASSERT_TRUE(tray->GetWidget());
167
168   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
169
170   // Ensure that closing the bubble destroys it.
171   ASSERT_TRUE(tray->CloseSystemBubble());
172   RunAllPendingInMessageLoop();
173   ASSERT_FALSE(tray->CloseSystemBubble());
174 }
175
176 // Opening and closing the bubble should change the coloring of the tray.
177 TEST_F(SystemTrayTest, SystemTrayColoring) {
178   SystemTray* tray = GetSystemTray();
179   ASSERT_TRUE(tray->GetWidget());
180   // At the beginning the tray coloring is not active.
181   ASSERT_FALSE(tray->draw_background_as_active());
182
183   // Showing the system bubble should show the background as active.
184   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
185   ASSERT_TRUE(tray->draw_background_as_active());
186
187   // Closing the system menu should change the coloring back to normal.
188   ASSERT_TRUE(tray->CloseSystemBubble());
189   RunAllPendingInMessageLoop();
190   ASSERT_FALSE(tray->draw_background_as_active());
191 }
192
193 // Closing the system bubble through an alignment change should change the
194 // system tray coloring back to normal.
195 TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) {
196   SystemTray* tray = GetSystemTray();
197   ASSERT_TRUE(tray->GetWidget());
198   ShelfLayoutManager* manager =
199       Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
200   manager->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
201   // At the beginning the tray coloring is not active.
202   ASSERT_FALSE(tray->draw_background_as_active());
203
204   // Showing the system bubble should show the background as active.
205   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
206   ASSERT_TRUE(tray->draw_background_as_active());
207
208   // Changing the alignment should close the system bubble and change the
209   // background color.
210   manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
211   ASSERT_FALSE(tray->draw_background_as_active());
212   RunAllPendingInMessageLoop();
213   // The bubble should already be closed by now.
214   ASSERT_FALSE(tray->CloseSystemBubble());
215 }
216
217 TEST_F(SystemTrayTest, SystemTrayTestItems) {
218   SystemTray* tray = GetSystemTray();
219   ASSERT_TRUE(tray->GetWidget());
220
221   TestItem* test_item = new TestItem;
222   TestItem* detailed_item = new TestItem;
223   tray->AddTrayItem(test_item);
224   tray->AddTrayItem(detailed_item);
225
226   // Check items have been added
227   const std::vector<SystemTrayItem*>& items = tray->GetTrayItems();
228   ASSERT_TRUE(
229       std::find(items.begin(), items.end(), test_item) != items.end());
230   ASSERT_TRUE(
231       std::find(items.begin(), items.end(), detailed_item) != items.end());
232
233   // Ensure the tray views are created.
234   ASSERT_TRUE(test_item->tray_view() != NULL);
235   ASSERT_TRUE(detailed_item->tray_view() != NULL);
236
237   // Ensure a default views are created.
238   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
239   ASSERT_TRUE(test_item->default_view() != NULL);
240   ASSERT_TRUE(detailed_item->default_view() != NULL);
241
242   // Show the detailed view, ensure it's created and the default view destroyed.
243   tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
244   RunAllPendingInMessageLoop();
245   ASSERT_TRUE(test_item->default_view() == NULL);
246   ASSERT_TRUE(detailed_item->detailed_view() != NULL);
247
248   // Show the default view, ensure it's created and the detailed view destroyed.
249   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
250   RunAllPendingInMessageLoop();
251   ASSERT_TRUE(test_item->default_view() != NULL);
252   ASSERT_TRUE(detailed_item->detailed_view() == NULL);
253 }
254
255 TEST_F(SystemTrayTest, SystemTrayNoViewItems) {
256   SystemTray* tray = GetSystemTray();
257   ASSERT_TRUE(tray->GetWidget());
258
259   // Verify that no crashes occur on items lacking some views.
260   TestNoViewItem* no_view_item = new TestNoViewItem;
261   tray->AddTrayItem(no_view_item);
262   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
263   tray->ShowDetailedView(no_view_item, 0, false, BUBBLE_USE_EXISTING);
264   RunAllPendingInMessageLoop();
265 }
266
267 TEST_F(SystemTrayTest, TrayWidgetAutoResizes) {
268   SystemTray* tray = GetSystemTray();
269   ASSERT_TRUE(tray->GetWidget());
270
271   // Add an initial tray item so that the tray gets laid out correctly.
272   TestItem* initial_item = new TestItem;
273   tray->AddTrayItem(initial_item);
274
275   gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
276
277   TestItem* new_item = new TestItem;
278   tray->AddTrayItem(new_item);
279
280   gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size();
281
282   // Adding the new item should change the size of the tray.
283   EXPECT_NE(initial_size.ToString(), new_size.ToString());
284
285   // Hiding the tray view of the new item should also change the size of the
286   // tray.
287   new_item->tray_view()->SetVisible(false);
288   EXPECT_EQ(initial_size.ToString(),
289             tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
290
291   new_item->tray_view()->SetVisible(true);
292   EXPECT_EQ(new_size.ToString(),
293             tray->GetWidget()->GetWindowBoundsInScreen().size().ToString());
294 }
295
296 TEST_F(SystemTrayTest, SystemTrayNotifications) {
297   SystemTray* tray = GetSystemTray();
298   ASSERT_TRUE(tray->GetWidget());
299
300   TestItem* test_item = new TestItem;
301   TestItem* detailed_item = new TestItem;
302   tray->AddTrayItem(test_item);
303   tray->AddTrayItem(detailed_item);
304
305   // Ensure the tray views are created.
306   ASSERT_TRUE(test_item->tray_view() != NULL);
307   ASSERT_TRUE(detailed_item->tray_view() != NULL);
308
309   // Ensure a notification view is created.
310   tray->ShowNotificationView(test_item);
311   ASSERT_TRUE(test_item->notification_view() != NULL);
312
313   // Show the default view, notification view should remain.
314   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
315   RunAllPendingInMessageLoop();
316   ASSERT_TRUE(test_item->notification_view() != NULL);
317
318   // Show the detailed view, ensure the notification view remains.
319   tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW);
320   RunAllPendingInMessageLoop();
321   ASSERT_TRUE(detailed_item->detailed_view() != NULL);
322   ASSERT_TRUE(test_item->notification_view() != NULL);
323
324   // Hide the detailed view, ensure the notification view still exists.
325   ASSERT_TRUE(tray->CloseSystemBubble());
326   RunAllPendingInMessageLoop();
327   ASSERT_TRUE(detailed_item->detailed_view() == NULL);
328   ASSERT_TRUE(test_item->notification_view() != NULL);
329 }
330
331 TEST_F(SystemTrayTest, BubbleCreationTypesTest) {
332   SystemTray* tray = GetSystemTray();
333   ASSERT_TRUE(tray->GetWidget());
334
335   TestItem* test_item = new TestItem;
336   tray->AddTrayItem(test_item);
337
338   // Ensure the tray views are created.
339   ASSERT_TRUE(test_item->tray_view() != NULL);
340
341   // Show the default view, ensure the notification view is destroyed.
342   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
343   RunAllPendingInMessageLoop();
344
345   views::Widget* widget = test_item->default_view()->GetWidget();
346   gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen();
347
348   tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING);
349   RunAllPendingInMessageLoop();
350
351   EXPECT_FALSE(test_item->default_view());
352
353   EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view()->GetWidget()->
354       GetWindowBoundsInScreen().ToString());
355   EXPECT_EQ(widget, test_item->detailed_view()->GetWidget());
356
357   tray->ShowDefaultView(BUBBLE_USE_EXISTING);
358   RunAllPendingInMessageLoop();
359
360   EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view()->GetWidget()->
361       GetWindowBoundsInScreen().ToString());
362   EXPECT_EQ(widget, test_item->default_view()->GetWidget());
363 }
364
365 // Tests that the tray is laid out properly and is fully contained within
366 // the shelf.
367 TEST_F(SystemTrayTest, TrayBoundsInWidget) {
368   ShelfLayoutManager* manager =
369       Shell::GetPrimaryRootWindowController()->shelf()->shelf_layout_manager();
370   StatusAreaWidget* widget =
371       Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
372   SystemTray* tray = widget->system_tray();
373
374   // Test in bottom alignment.
375   manager->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
376   gfx::Rect window_bounds = widget->GetWindowBoundsInScreen();
377   gfx::Rect tray_bounds = tray->GetBoundsInScreen();
378   EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
379   EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
380   EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
381   EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
382
383   // Test in the left alignment.
384   manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
385   window_bounds = widget->GetWindowBoundsInScreen();
386   tray_bounds = tray->GetBoundsInScreen();
387   EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
388   EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
389   EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
390   EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
391
392   // Test in the right alignment.
393   manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
394   window_bounds = widget->GetWindowBoundsInScreen();
395   tray_bounds = tray->GetBoundsInScreen();
396   EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
397   EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
398   EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
399   EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
400 }
401
402 TEST_F(SystemTrayTest, PersistentBubble) {
403   SystemTray* tray = GetSystemTray();
404   ASSERT_TRUE(tray->GetWidget());
405
406   TestItem* test_item = new TestItem;
407   tray->AddTrayItem(test_item);
408
409   scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
410
411   // Tests for usual default view.
412   // Activating window.
413   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
414   ASSERT_TRUE(tray->HasSystemBubble());
415   wm::ActivateWindow(window.get());
416   base::RunLoop().RunUntilIdle();
417   ASSERT_FALSE(tray->HasSystemBubble());
418
419   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
420   ASSERT_TRUE(tray->HasSystemBubble());
421   {
422     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
423                                        gfx::Point(5, 5));
424     generator.ClickLeftButton();
425     ASSERT_FALSE(tray->HasSystemBubble());
426   }
427
428   // Same tests for persistent default view.
429   tray->ShowPersistentDefaultView();
430   ASSERT_TRUE(tray->HasSystemBubble());
431   wm::ActivateWindow(window.get());
432   base::RunLoop().RunUntilIdle();
433   ASSERT_TRUE(tray->HasSystemBubble());
434
435   {
436     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
437                                        gfx::Point(5, 5));
438     generator.ClickLeftButton();
439     ASSERT_TRUE(tray->HasSystemBubble());
440   }
441 }
442
443 #if defined(OS_CHROMEOS)
444 // Accessibility/Settings tray items are available only on cros.
445 #define MAYBE_WithSystemModal WithSystemModal
446 #else
447 #define MAYBE_WithSystemModal DISABLED_WithSystemModal
448 #endif
449 TEST_F(SystemTrayTest, MAYBE_WithSystemModal) {
450   // Check if the accessibility item is created even with system modal
451   // dialog.
452   Shell::GetInstance()->accessibility_delegate()->SetVirtualKeyboardEnabled(
453       true);
454   views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
455       new ModalWidgetDelegate(),
456       Shell::GetPrimaryRootWindow(),
457       gfx::Rect(0, 0, 100, 100));
458   widget->Show();
459
460   SystemTray* tray = GetSystemTray();
461   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
462
463   ASSERT_TRUE(tray->HasSystemBubble());
464   const views::View* accessibility =
465       tray->GetSystemBubble()->bubble_view()->GetViewByID(
466           test::kAccessibilityTrayItemViewId);
467   ASSERT_TRUE(accessibility);
468   EXPECT_TRUE(accessibility->visible());
469   EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetViewByID(
470       test::kSettingsTrayItemViewId));
471
472   widget->Close();
473
474   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
475   // System modal is gone. The bubble should now contains settings
476   // as well.
477   accessibility = tray->GetSystemBubble()->bubble_view()->GetViewByID(
478       test::kAccessibilityTrayItemViewId);
479   ASSERT_TRUE(accessibility);
480   EXPECT_TRUE(accessibility->visible());
481
482   const views::View* settings =
483       tray->GetSystemBubble()->bubble_view()->GetViewByID(
484           test::kSettingsTrayItemViewId);
485   ASSERT_TRUE(settings);
486   EXPECT_TRUE(settings->visible());
487 }
488
489 // Tests that if SetVisible(true) is called while animating to hidden that the
490 // tray becomes visible, and stops animating to hidden.
491 TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) {
492   SystemTray* tray = GetSystemTray();
493   ASSERT_TRUE(tray->visible());
494
495   scoped_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration;
496   animation_duration.reset(
497       new ui::ScopedAnimationDurationScaleMode(
498           ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
499   tray->SetVisible(false);
500   EXPECT_TRUE(tray->visible());
501   EXPECT_EQ(0.0f, tray->layer()->GetTargetOpacity());
502
503   tray->SetVisible(true);
504   animation_duration.reset();
505   tray->layer()->GetAnimator()->StopAnimating();
506   EXPECT_TRUE(tray->visible());
507   EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity());
508 }
509
510 #if defined(OS_CHROMEOS)
511 // Tests that touch on an item in the system bubble triggers it to become
512 // active.
513 TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedback) {
514   SystemTray* tray = GetSystemTray();
515   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
516
517   TrayPopupItemContainer* view =
518       static_cast<TrayPopupItemContainer*>(tray->GetSystemBubble()->
519           bubble_view()->child_at(0));
520   EXPECT_FALSE(view->active());
521
522   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
523   generator.set_current_location(view->GetBoundsInScreen().CenterPoint());
524   generator.PressTouch();
525   RunAllPendingInMessageLoop();
526   EXPECT_TRUE(view->active());
527
528   generator.ReleaseTouch();
529   RunAllPendingInMessageLoop();
530   EXPECT_FALSE(view->active());
531 }
532
533 // Tests that touch events on an item in the system bubble cause it to stop
534 // being active.
535 TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedbackCancellation) {
536   SystemTray* tray = GetSystemTray();
537   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
538
539   TrayPopupItemContainer* view =
540       static_cast<TrayPopupItemContainer*>(tray->GetSystemBubble()->
541           bubble_view()->child_at(0));
542   EXPECT_FALSE(view->active());
543
544   gfx::Rect view_bounds = view->GetBoundsInScreen();
545   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
546   generator.set_current_location(view_bounds.CenterPoint());
547   generator.PressTouch();
548   RunAllPendingInMessageLoop();
549   EXPECT_TRUE(view->active());
550
551   gfx::Point move_point(view_bounds.x(), view_bounds.CenterPoint().y());
552   generator.MoveTouch(move_point);
553   RunAllPendingInMessageLoop();
554   EXPECT_FALSE(view->active());
555
556   generator.set_current_location(move_point);
557   generator.ReleaseTouch();
558   RunAllPendingInMessageLoop();
559   EXPECT_FALSE(view->active());
560 }
561 #endif  // OS_CHROMEOS
562
563 }  // namespace test
564 }  // namespace ash