Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / wm / immersive_fullscreen_controller_unittest.cc
1 // Copyright 2013 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/wm/immersive_fullscreen_controller.h"
6
7 #include "ash/display/display_manager.h"
8 #include "ash/display/mouse_cursor_event_filter.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/shelf/shelf_layout_manager.h"
11 #include "ash/shelf/shelf_types.h"
12 #include "ash/shell.h"
13 #include "ash/test/ash_test_base.h"
14 #include "ash/wm/window_state.h"
15 #include "ui/aura/client/aura_constants.h"
16 #include "ui/aura/client/cursor_client.h"
17 #include "ui/aura/env.h"
18 #include "ui/aura/test/test_window_delegate.h"
19 #include "ui/aura/window.h"
20 #include "ui/aura/window_event_dispatcher.h"
21 #include "ui/events/event_utils.h"
22 #include "ui/events/test/event_generator.h"
23 #include "ui/events/test/test_event_handler.h"
24 #include "ui/gfx/animation/slide_animation.h"
25 #include "ui/views/bubble/bubble_delegate.h"
26 #include "ui/views/controls/native/native_view_host.h"
27 #include "ui/views/view.h"
28 #include "ui/views/widget/widget.h"
29
30 namespace ash {
31
32 namespace {
33
34 class MockImmersiveFullscreenControllerDelegate
35     : public ImmersiveFullscreenController::Delegate {
36  public:
37   MockImmersiveFullscreenControllerDelegate(views::View* top_container_view)
38       : top_container_view_(top_container_view),
39         enabled_(false),
40         visible_fraction_(1) {
41   }
42   virtual ~MockImmersiveFullscreenControllerDelegate() {}
43
44   // ImmersiveFullscreenController::Delegate overrides:
45   virtual void OnImmersiveRevealStarted() OVERRIDE {
46     enabled_ = true;
47     visible_fraction_ = 0;
48   }
49   virtual void OnImmersiveRevealEnded() OVERRIDE {
50     visible_fraction_ = 0;
51   }
52   virtual void OnImmersiveFullscreenExited() OVERRIDE {
53     enabled_ = false;
54     visible_fraction_ = 1;
55   }
56   virtual void SetVisibleFraction(double visible_fraction) OVERRIDE {
57     visible_fraction_ = visible_fraction;
58   }
59   virtual std::vector<gfx::Rect> GetVisibleBoundsInScreen() const OVERRIDE {
60     std::vector<gfx::Rect> bounds_in_screen;
61     bounds_in_screen.push_back(top_container_view_->GetBoundsInScreen());
62     return bounds_in_screen;
63   }
64
65   bool is_enabled() const {
66     return enabled_;
67   }
68
69   double visible_fraction() const {
70     return visible_fraction_;
71   }
72
73  private:
74   views::View* top_container_view_;
75   bool enabled_;
76   double visible_fraction_;
77
78   DISALLOW_COPY_AND_ASSIGN(MockImmersiveFullscreenControllerDelegate);
79 };
80
81 class ConsumeEventHandler : public ui::test::TestEventHandler {
82  public:
83   ConsumeEventHandler() {}
84   virtual ~ConsumeEventHandler() {}
85
86  private:
87   virtual void OnEvent(ui::Event* event) OVERRIDE {
88     ui::test::TestEventHandler::OnEvent(event);
89     if (event->cancelable())
90       event->SetHandled();
91   }
92
93   DISALLOW_COPY_AND_ASSIGN(ConsumeEventHandler);
94 };
95
96 }  // namespace
97
98 /////////////////////////////////////////////////////////////////////////////
99
100 class ImmersiveFullscreenControllerTest : public ash::test::AshTestBase {
101  public:
102   enum Modality {
103     MODALITY_MOUSE,
104     MODALITY_GESTURE_TAP,
105     MODALITY_GESTURE_SCROLL
106   };
107
108   ImmersiveFullscreenControllerTest()
109       : widget_(NULL),
110         top_container_(NULL),
111         content_view_(NULL) {}
112   virtual ~ImmersiveFullscreenControllerTest() {}
113
114   ImmersiveFullscreenController* controller() {
115     return controller_.get();
116   }
117
118   views::NativeViewHost* content_view() {
119     return content_view_;
120   }
121
122   views::View* top_container() {
123     return top_container_;
124   }
125
126   views::Widget* widget() { return widget_; }
127
128   aura::Window* window() {
129     return widget_->GetNativeWindow();
130   }
131
132   MockImmersiveFullscreenControllerDelegate* delegate() {
133     return delegate_.get();
134   }
135
136   // Access to private data from the controller.
137   bool top_edge_hover_timer_running() const {
138     return controller_->top_edge_hover_timer_.IsRunning();
139   }
140   int mouse_x_when_hit_top() const {
141     return controller_->mouse_x_when_hit_top_in_screen_;
142   }
143
144   // ash::test::AshTestBase overrides:
145   virtual void SetUp() OVERRIDE {
146     ash::test::AshTestBase::SetUp();
147
148     widget_ = new views::Widget();
149     views::Widget::InitParams params;
150     params.context = CurrentContext();
151     widget_->Init(params);
152     widget_->Show();
153
154     window()->SetProperty(aura::client::kShowStateKey,
155                           ui::SHOW_STATE_FULLSCREEN);
156
157     gfx::Size window_size = widget_->GetWindowBoundsInScreen().size();
158     content_view_ = new views::NativeViewHost();
159     content_view_->SetBounds(0, 0, window_size.width(), window_size.height());
160     widget_->GetContentsView()->AddChildView(content_view_);
161
162     top_container_ = new views::View();
163     top_container_->SetBounds(
164         0, 0, window_size.width(), 100);
165     top_container_->SetFocusable(true);
166     widget_->GetContentsView()->AddChildView(top_container_);
167
168     delegate_.reset(
169         new MockImmersiveFullscreenControllerDelegate(top_container_));
170     controller_.reset(new ImmersiveFullscreenController);
171     controller_->Init(delegate_.get(), widget_, top_container_);
172     controller_->SetupForTest();
173
174     // The mouse is moved so that it is not over |top_container_| by
175     // AshTestBase.
176   }
177
178   // Enables / disables immersive fullscreen.
179   void SetEnabled(bool enabled) {
180     controller_->SetEnabled(ImmersiveFullscreenController::WINDOW_TYPE_OTHER,
181                             enabled);
182   }
183
184   // Attempt to reveal the top-of-window views via |modality|.
185   // The top-of-window views can only be revealed via mouse hover or a gesture.
186   void AttemptReveal(Modality modality) {
187     ASSERT_NE(modality, MODALITY_GESTURE_TAP);
188     AttemptRevealStateChange(true, modality);
189   }
190
191   // Attempt to unreveal the top-of-window views via |modality|. The
192   // top-of-window views can be unrevealed via any modality.
193   void AttemptUnreveal(Modality modality) {
194     AttemptRevealStateChange(false, modality);
195   }
196
197   // Sets whether the mouse is hovered above |top_container_|.
198   // SetHovered(true) moves the mouse over the |top_container_| but does not
199   // move it to the top of the screen so will not initiate a reveal.
200   void SetHovered(bool is_mouse_hovered) {
201     MoveMouse(0, is_mouse_hovered ? 10 : top_container_->height() + 100);
202   }
203
204   // Move the mouse to the given coordinates. The coordinates should be in
205   // |top_container_| coordinates.
206   void MoveMouse(int x, int y) {
207     gfx::Point screen_position(x, y);
208     views::View::ConvertPointToScreen(top_container_, &screen_position);
209     GetEventGenerator().MoveMouseTo(screen_position.x(), screen_position.y());
210
211     // If the top edge timer started running as a result of the mouse move, run
212     // the task which occurs after the timer delay. This reveals the
213     // top-of-window views synchronously if the mouse is hovered at the top of
214     // the screen.
215     if (controller()->top_edge_hover_timer_.IsRunning()) {
216       controller()->top_edge_hover_timer_.user_task().Run();
217       controller()->top_edge_hover_timer_.Stop();
218     }
219   }
220
221  private:
222   // Attempt to change the revealed state to |revealed| via |modality|.
223   void AttemptRevealStateChange(bool revealed, Modality modality) {
224     // Compute the event position in |top_container_| coordinates.
225     gfx::Point event_position(0, revealed ? 0 : top_container_->height() + 100);
226     switch (modality) {
227       case MODALITY_MOUSE: {
228         MoveMouse(event_position.x(), event_position.y());
229         break;
230       }
231       case MODALITY_GESTURE_TAP: {
232         gfx::Point screen_position = event_position;
233         views::View::ConvertPointToScreen(top_container_, &screen_position);
234         ui::test::EventGenerator& event_generator(GetEventGenerator());
235         event_generator.MoveTouch(event_position);
236         event_generator.PressTouch();
237         event_generator.ReleaseTouch();
238         break;
239       }
240       case MODALITY_GESTURE_SCROLL: {
241         gfx::Point start(0, revealed ? 0 : top_container_->height() - 2);
242         gfx::Vector2d scroll_delta(0, 40);
243         gfx::Point end = revealed ? start + scroll_delta : start - scroll_delta;
244         views::View::ConvertPointToScreen(top_container_, &start);
245         views::View::ConvertPointToScreen(top_container_, &end);
246         ui::test::EventGenerator& event_generator(GetEventGenerator());
247         event_generator.GestureScrollSequence(
248             start, end,
249             base::TimeDelta::FromMilliseconds(30), 1);
250         break;
251       }
252     }
253   }
254
255   scoped_ptr<ImmersiveFullscreenController> controller_;
256   scoped_ptr<MockImmersiveFullscreenControllerDelegate> delegate_;
257   views::Widget* widget_;  // Owned by the native widget.
258   views::View* top_container_;  // Owned by |widget_|'s root-view.
259   views::NativeViewHost* content_view_;  // Owned by |widget_|'s root-view.
260
261   DISALLOW_COPY_AND_ASSIGN(ImmersiveFullscreenControllerTest);
262 };
263
264 // Test the initial state and that the delegate gets notified of the
265 // top-of-window views getting hidden and revealed.
266 TEST_F(ImmersiveFullscreenControllerTest, Delegate) {
267   // Initial state.
268   EXPECT_FALSE(controller()->IsEnabled());
269   EXPECT_FALSE(controller()->IsRevealed());
270   EXPECT_FALSE(delegate()->is_enabled());
271
272   // Enabling initially hides the top views.
273   SetEnabled(true);
274   EXPECT_TRUE(controller()->IsEnabled());
275   EXPECT_FALSE(controller()->IsRevealed());
276   EXPECT_TRUE(delegate()->is_enabled());
277   EXPECT_EQ(0, delegate()->visible_fraction());
278
279   // Revealing shows the top views.
280   AttemptReveal(MODALITY_MOUSE);
281   EXPECT_TRUE(controller()->IsEnabled());
282   EXPECT_TRUE(controller()->IsRevealed());
283   EXPECT_TRUE(delegate()->is_enabled());
284   EXPECT_EQ(1, delegate()->visible_fraction());
285
286   // Disabling ends the immersive reveal.
287   SetEnabled(false);
288   EXPECT_FALSE(controller()->IsEnabled());
289   EXPECT_FALSE(controller()->IsRevealed());
290   EXPECT_FALSE(delegate()->is_enabled());
291 }
292
293 // GetRevealedLock() specific tests.
294 TEST_F(ImmersiveFullscreenControllerTest, RevealedLock) {
295   scoped_ptr<ImmersiveRevealedLock> lock1;
296   scoped_ptr<ImmersiveRevealedLock> lock2;
297
298   // Immersive fullscreen is not on by default.
299   EXPECT_FALSE(controller()->IsEnabled());
300
301   // 1) Test acquiring and releasing a revealed state lock while immersive
302   // fullscreen is disabled. Acquiring or releasing the lock should have no
303   // effect till immersive fullscreen is enabled.
304   lock1.reset(controller()->GetRevealedLock(
305       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
306   EXPECT_FALSE(controller()->IsEnabled());
307   EXPECT_FALSE(controller()->IsRevealed());
308
309   // Immersive fullscreen should start in the revealed state due to the lock.
310   SetEnabled(true);
311   EXPECT_TRUE(controller()->IsEnabled());
312   EXPECT_TRUE(controller()->IsRevealed());
313
314   SetEnabled(false);
315   EXPECT_FALSE(controller()->IsEnabled());
316   EXPECT_FALSE(controller()->IsRevealed());
317
318   lock1.reset();
319   EXPECT_FALSE(controller()->IsEnabled());
320   EXPECT_FALSE(controller()->IsRevealed());
321
322   // Immersive fullscreen should start in the closed state because the lock is
323   // no longer held.
324   SetEnabled(true);
325   EXPECT_TRUE(controller()->IsEnabled());
326   EXPECT_FALSE(controller()->IsRevealed());
327
328   // 2) Test that acquiring a lock reveals the top-of-window views if they are
329   // hidden.
330   lock1.reset(controller()->GetRevealedLock(
331       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
332   EXPECT_TRUE(controller()->IsRevealed());
333
334   // 3) Test that the top-of-window views are only hidden when all of the locks
335   // are released.
336   lock2.reset(controller()->GetRevealedLock(
337       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
338   lock1.reset();
339   EXPECT_TRUE(controller()->IsRevealed());
340
341   lock2.reset();
342   EXPECT_FALSE(controller()->IsRevealed());
343 }
344
345 // Test mouse event processing for top-of-screen reveal triggering.
346 TEST_F(ImmersiveFullscreenControllerTest, OnMouseEvent) {
347   // Set up initial state.
348   SetEnabled(true);
349   ASSERT_TRUE(controller()->IsEnabled());
350   ASSERT_FALSE(controller()->IsRevealed());
351
352   ui::test::EventGenerator& event_generator(GetEventGenerator());
353
354   gfx::Rect top_container_bounds_in_screen =
355       top_container()->GetBoundsInScreen();
356   // A position along the top edge of TopContainerView in screen coordinates.
357   gfx::Point top_edge_pos(top_container_bounds_in_screen.x() + 100,
358                           top_container_bounds_in_screen.y());
359
360   // Mouse wheel event does nothing.
361   ui::MouseEvent wheel(
362       ui::ET_MOUSEWHEEL, top_edge_pos, top_edge_pos, ui::EF_NONE, ui::EF_NONE);
363   event_generator.Dispatch(&wheel);
364   EXPECT_FALSE(top_edge_hover_timer_running());
365
366   // Move to top edge of screen starts hover timer running. We cannot use
367   // MoveMouse() because MoveMouse() stops the timer if it started running.
368   event_generator.MoveMouseTo(top_edge_pos);
369   EXPECT_TRUE(top_edge_hover_timer_running());
370   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
371
372   // Moving |ImmersiveFullscreenControllerTest::kMouseRevealBoundsHeight| down
373   // from the top edge stops it.
374   event_generator.MoveMouseBy(0,
375       ImmersiveFullscreenController::kMouseRevealBoundsHeight);
376   EXPECT_FALSE(top_edge_hover_timer_running());
377
378   // Moving back to the top starts the timer again.
379   event_generator.MoveMouseTo(top_edge_pos);
380   EXPECT_TRUE(top_edge_hover_timer_running());
381   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
382
383   // Slight move to the right keeps the timer running for the same hit point.
384   event_generator.MoveMouseBy(1, 0);
385   EXPECT_TRUE(top_edge_hover_timer_running());
386   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
387
388   // Moving back to the left also keeps the timer running.
389   event_generator.MoveMouseBy(-1, 0);
390   EXPECT_TRUE(top_edge_hover_timer_running());
391   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
392
393   // Large move right restarts the timer (so it is still running) and considers
394   // this a new hit at the top.
395   event_generator.MoveMouseTo(top_edge_pos.x() + 100, top_edge_pos.y());
396   EXPECT_TRUE(top_edge_hover_timer_running());
397   EXPECT_EQ(top_edge_pos.x() + 100, mouse_x_when_hit_top());
398
399   // Moving off the top edge horizontally stops the timer.
400   event_generator.MoveMouseTo(top_container_bounds_in_screen.right() + 1,
401                               top_container_bounds_in_screen.y());
402   EXPECT_FALSE(top_edge_hover_timer_running());
403
404   // Once revealed, a move just a little below the top container doesn't end a
405   // reveal.
406   AttemptReveal(MODALITY_MOUSE);
407   event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
408                               top_container_bounds_in_screen.bottom() + 1);
409   EXPECT_TRUE(controller()->IsRevealed());
410
411   // Once revealed, clicking just below the top container ends the reveal.
412   event_generator.ClickLeftButton();
413   EXPECT_FALSE(controller()->IsRevealed());
414
415   // Moving a lot below the top container ends a reveal.
416   AttemptReveal(MODALITY_MOUSE);
417   EXPECT_TRUE(controller()->IsRevealed());
418   event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
419                               top_container_bounds_in_screen.bottom() + 50);
420   EXPECT_FALSE(controller()->IsRevealed());
421
422   // The mouse position cannot cause a reveal when the top container's widget
423   // has capture.
424   views::Widget* widget = top_container()->GetWidget();
425   widget->SetCapture(top_container());
426   AttemptReveal(MODALITY_MOUSE);
427   EXPECT_FALSE(controller()->IsRevealed());
428   widget->ReleaseCapture();
429
430   // The mouse position cannot end the reveal while the top container's widget
431   // has capture.
432   AttemptReveal(MODALITY_MOUSE);
433   EXPECT_TRUE(controller()->IsRevealed());
434   widget->SetCapture(top_container());
435   event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
436                               top_container_bounds_in_screen.bottom() + 51);
437   EXPECT_TRUE(controller()->IsRevealed());
438
439   // Releasing capture should end the reveal.
440   widget->ReleaseCapture();
441   EXPECT_FALSE(controller()->IsRevealed());
442 }
443
444 // Test mouse event processing for top-of-screen reveal triggering when the
445 // top container's widget is inactive.
446 TEST_F(ImmersiveFullscreenControllerTest, Inactive) {
447   // Set up initial state.
448   views::Widget* popup_widget = views::Widget::CreateWindowWithContextAndBounds(
449       NULL,
450       CurrentContext(),
451       gfx::Rect(0, 0, 200, 200));
452   popup_widget->Show();
453   ASSERT_FALSE(top_container()->GetWidget()->IsActive());
454
455   SetEnabled(true);
456   ASSERT_TRUE(controller()->IsEnabled());
457   ASSERT_FALSE(controller()->IsRevealed());
458
459   gfx::Rect top_container_bounds_in_screen =
460       top_container()->GetBoundsInScreen();
461   gfx::Rect popup_bounds_in_screen = popup_widget->GetWindowBoundsInScreen();
462   ASSERT_EQ(top_container_bounds_in_screen.origin().ToString(),
463             popup_bounds_in_screen.origin().ToString());
464   ASSERT_GT(top_container_bounds_in_screen.right(),
465             popup_bounds_in_screen.right());
466
467   // The top-of-window views should stay hidden if the cursor is at the top edge
468   // but above an obscured portion of the top-of-window views.
469   MoveMouse(popup_bounds_in_screen.x(),
470             top_container_bounds_in_screen.y());
471   EXPECT_FALSE(controller()->IsRevealed());
472
473   // The top-of-window views should reveal if the cursor is at the top edge and
474   // above an unobscured portion of the top-of-window views.
475   MoveMouse(top_container_bounds_in_screen.right() - 1,
476             top_container_bounds_in_screen.y());
477   EXPECT_TRUE(controller()->IsRevealed());
478
479   // The top-of-window views should stay revealed if the cursor is moved off
480   // of the top edge.
481   MoveMouse(top_container_bounds_in_screen.right() - 1,
482             top_container_bounds_in_screen.bottom() - 1);
483   EXPECT_TRUE(controller()->IsRevealed());
484
485   // Moving way off of the top-of-window views should end the immersive reveal.
486   MoveMouse(top_container_bounds_in_screen.right() - 1,
487             top_container_bounds_in_screen.bottom() + 50);
488   EXPECT_FALSE(controller()->IsRevealed());
489
490   // Moving way off of the top-of-window views in a region where the
491   // top-of-window views are obscured should also end the immersive reveal.
492   // Ideally, the immersive reveal would end immediately when the cursor moves
493   // to an obscured portion of the top-of-window views.
494   MoveMouse(top_container_bounds_in_screen.right() - 1,
495             top_container_bounds_in_screen.y());
496   EXPECT_TRUE(controller()->IsRevealed());
497   MoveMouse(top_container_bounds_in_screen.x(),
498             top_container_bounds_in_screen.bottom() + 50);
499   EXPECT_FALSE(controller()->IsRevealed());
500 }
501
502 // Test mouse event processing for top-of-screen reveal triggering when the user
503 // has a vertical display layout (primary display above/below secondary display)
504 // and the immersive fullscreen window is on the bottom display.
505 TEST_F(ImmersiveFullscreenControllerTest, MouseEventsVerticalDisplayLayout) {
506   if (!SupportsMultipleDisplays())
507     return;
508
509   // Set up initial state.
510   UpdateDisplay("800x600,800x600");
511   ash::DisplayLayout display_layout(ash::DisplayLayout::TOP, 0);
512   ash::Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
513       display_layout);
514
515   SetEnabled(true);
516   ASSERT_TRUE(controller()->IsEnabled());
517   ASSERT_FALSE(controller()->IsRevealed());
518
519   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
520   ASSERT_EQ(root_windows[0],
521             top_container()->GetWidget()->GetNativeWindow()->GetRootWindow());
522
523   gfx::Rect primary_root_window_bounds_in_screen =
524       root_windows[0]->GetBoundsInScreen();
525   // Do not set |x| to the root window's x position because the display's
526   // corners have special behavior.
527   int x = primary_root_window_bounds_in_screen.x() + 10;
528   // The y position of the top edge of the primary display.
529   int y_top_edge = primary_root_window_bounds_in_screen.y();
530
531   ui::test::EventGenerator& event_generator(GetEventGenerator());
532
533   // Moving right below the top edge starts the hover timer running. We
534   // cannot use MoveMouse() because MoveMouse() stops the timer if it started
535   // running.
536   event_generator.MoveMouseTo(x, y_top_edge + 1);
537   EXPECT_TRUE(top_edge_hover_timer_running());
538   EXPECT_EQ(y_top_edge + 1,
539             aura::Env::GetInstance()->last_mouse_location().y());
540
541   // The timer should continue running if the user moves the mouse to the top
542   // edge even though the mouse is warped to the secondary display.
543   event_generator.MoveMouseTo(x, y_top_edge);
544   EXPECT_TRUE(top_edge_hover_timer_running());
545
546   // The timer should continue running if the user overshoots the top edge
547   // a bit.
548   event_generator.MoveMouseTo(x, y_top_edge - 2);
549   EXPECT_TRUE(top_edge_hover_timer_running());
550
551   // The timer should stop running if the user overshoots the top edge by
552   // a lot.
553   event_generator.MoveMouseTo(x, y_top_edge - 20);
554   EXPECT_FALSE(top_edge_hover_timer_running());
555
556   // The timer should not start if the user moves the mouse to the bottom of the
557   // secondary display without crossing the top edge first.
558   event_generator.MoveMouseTo(x, y_top_edge - 2);
559
560   // Reveal the top-of-window views by overshooting the top edge slightly.
561   event_generator.MoveMouseTo(x, y_top_edge + 1);
562   // MoveMouse() runs the timer task.
563   MoveMouse(x, y_top_edge - 2);
564   EXPECT_TRUE(controller()->IsRevealed());
565
566   // The top-of-window views should stay revealed if the user moves the mouse
567   // around in the bottom region of the secondary display.
568   event_generator.MoveMouseTo(x + 10, y_top_edge - 3);
569   EXPECT_TRUE(controller()->IsRevealed());
570
571   // The top-of-window views should hide if the user moves the mouse away from
572   // the bottom region of the secondary display.
573   event_generator.MoveMouseTo(x, y_top_edge - 20);
574   EXPECT_FALSE(controller()->IsRevealed());
575
576   // Test that it is possible to reveal the top-of-window views by overshooting
577   // the top edge slightly when the top container's widget is not active.
578   views::Widget* popup_widget = views::Widget::CreateWindowWithContextAndBounds(
579       NULL,
580       CurrentContext(),
581       gfx::Rect(0, 200, 100, 100));
582   popup_widget->Show();
583   ASSERT_FALSE(top_container()->GetWidget()->IsActive());
584   ASSERT_FALSE(top_container()->GetBoundsInScreen().Intersects(
585       popup_widget->GetWindowBoundsInScreen()));
586   event_generator.MoveMouseTo(x, y_top_edge + 1);
587   MoveMouse(x, y_top_edge - 2);
588   EXPECT_TRUE(controller()->IsRevealed());
589 }
590
591 // Test behavior when the mouse becomes hovered without moving.
592 TEST_F(ImmersiveFullscreenControllerTest, MouseHoveredWithoutMoving) {
593   SetEnabled(true);
594   scoped_ptr<ImmersiveRevealedLock> lock;
595
596   // 1) Test that if the mouse becomes hovered without the mouse moving due to a
597   // lock causing the top-of-window views to be revealed (and the mouse
598   // happening to be near the top of the screen), the top-of-window views do not
599   // hide till the mouse moves off of the top-of-window views.
600   SetHovered(true);
601   EXPECT_FALSE(controller()->IsRevealed());
602   lock.reset(controller()->GetRevealedLock(
603       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
604   EXPECT_TRUE(controller()->IsRevealed());
605   lock.reset();
606   EXPECT_TRUE(controller()->IsRevealed());
607   SetHovered(false);
608   EXPECT_FALSE(controller()->IsRevealed());
609
610   // 2) Test that if the mouse becomes hovered without moving because of a
611   // reveal in ImmersiveFullscreenController::SetEnabled(true) and there are no
612   // locks keeping the top-of-window views revealed, that mouse hover does not
613   // prevent the top-of-window views from closing.
614   SetEnabled(false);
615   SetHovered(true);
616   EXPECT_FALSE(controller()->IsRevealed());
617   SetEnabled(true);
618   EXPECT_FALSE(controller()->IsRevealed());
619
620   // 3) Test that if the mouse becomes hovered without moving because of a
621   // reveal in ImmersiveFullscreenController::SetEnabled(true) and there is a
622   // lock keeping the top-of-window views revealed, that the top-of-window views
623   // do not hide till the mouse moves off of the top-of-window views.
624   SetEnabled(false);
625   SetHovered(true);
626   lock.reset(controller()->GetRevealedLock(
627       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
628   EXPECT_FALSE(controller()->IsRevealed());
629   SetEnabled(true);
630   EXPECT_TRUE(controller()->IsRevealed());
631   lock.reset();
632   EXPECT_TRUE(controller()->IsRevealed());
633   SetHovered(false);
634   EXPECT_FALSE(controller()->IsRevealed());
635 }
636
637 // Test revealing the top-of-window views using one modality and ending
638 // the reveal via another. For instance, initiating the reveal via a SWIPE_OPEN
639 // edge gesture, switching to using the mouse and ending the reveal by moving
640 // the mouse off of the top-of-window views.
641 TEST_F(ImmersiveFullscreenControllerTest, DifferentModalityEnterExit) {
642   SetEnabled(true);
643   EXPECT_TRUE(controller()->IsEnabled());
644   EXPECT_FALSE(controller()->IsRevealed());
645
646   // Initiate reveal via gesture, end reveal via mouse.
647   AttemptReveal(MODALITY_GESTURE_SCROLL);
648   EXPECT_TRUE(controller()->IsRevealed());
649   MoveMouse(1, 1);
650   EXPECT_TRUE(controller()->IsRevealed());
651   AttemptUnreveal(MODALITY_MOUSE);
652   EXPECT_FALSE(controller()->IsRevealed());
653
654   // Initiate reveal via gesture, end reveal via touch.
655   AttemptReveal(MODALITY_GESTURE_SCROLL);
656   EXPECT_TRUE(controller()->IsRevealed());
657   AttemptUnreveal(MODALITY_GESTURE_TAP);
658   EXPECT_FALSE(controller()->IsRevealed());
659
660   // Initiate reveal via mouse, end reveal via gesture.
661   AttemptReveal(MODALITY_MOUSE);
662   EXPECT_TRUE(controller()->IsRevealed());
663   AttemptUnreveal(MODALITY_GESTURE_SCROLL);
664   EXPECT_FALSE(controller()->IsRevealed());
665
666   // Initiate reveal via mouse, end reveal via touch.
667   AttemptReveal(MODALITY_MOUSE);
668   EXPECT_TRUE(controller()->IsRevealed());
669   AttemptUnreveal(MODALITY_GESTURE_TAP);
670   EXPECT_FALSE(controller()->IsRevealed());
671 }
672
673 // Test when the SWIPE_CLOSE edge gesture closes the top-of-window views.
674 #if defined(OS_WIN)
675 // On Windows, touch events do not result in mouse events being disabled.  As
676 // a result, the last part of this test which ends the reveal via a gesture will
677 // not work correctly.  See crbug.com/332430, and the function
678 // ShouldHideCursorOnTouch() in compound_event_filter.cc.
679 #define MAYBE_EndRevealViaGesture DISABLED_EndRevealViaGesture
680 #else
681 #define MAYBE_EndRevealViaGesture EndRevealViaGesture
682 #endif
683 TEST_F(ImmersiveFullscreenControllerTest, MAYBE_EndRevealViaGesture) {
684   SetEnabled(true);
685   EXPECT_TRUE(controller()->IsEnabled());
686   EXPECT_FALSE(controller()->IsRevealed());
687
688   // A gesture should be able to close the top-of-window views when
689   // top-of-window views have focus.
690   AttemptReveal(MODALITY_MOUSE);
691   top_container()->RequestFocus();
692   EXPECT_TRUE(controller()->IsRevealed());
693   AttemptUnreveal(MODALITY_GESTURE_SCROLL);
694   EXPECT_FALSE(controller()->IsRevealed());
695
696   // The top-of-window views should no longer have focus. Clearing focus is
697   // important because it closes focus-related popup windows like the touch
698   // selection handles.
699   EXPECT_FALSE(top_container()->HasFocus());
700
701   // If some other code is holding onto a lock, a gesture should not be able to
702   // end the reveal.
703   AttemptReveal(MODALITY_MOUSE);
704   scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
705       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
706   EXPECT_TRUE(controller()->IsRevealed());
707   AttemptUnreveal(MODALITY_GESTURE_SCROLL);
708   EXPECT_TRUE(controller()->IsRevealed());
709   lock.reset();
710   EXPECT_FALSE(controller()->IsRevealed());
711 }
712
713 // Tests that touch-gesture can be used to reveal the top-of-window views when
714 // the child window consumes all events.
715 TEST_F(ImmersiveFullscreenControllerTest, RevealViaGestureChildConsumesEvents) {
716   // Enabling initially hides the top views.
717   SetEnabled(true);
718   EXPECT_TRUE(controller()->IsEnabled());
719   EXPECT_FALSE(controller()->IsRevealed());
720
721   aura::test::TestWindowDelegate child_delegate;
722   scoped_ptr<aura::Window> child(
723       CreateTestWindowInShellWithDelegateAndType(&child_delegate,
724                                                  ui::wm::WINDOW_TYPE_CONTROL,
725                                                  1234,
726                                                  gfx::Rect()));
727   content_view()->Attach(child.get());
728   child->Show();
729
730   ConsumeEventHandler handler;
731   child->AddPreTargetHandler(&handler);
732
733   // Reveal the top views using a touch-scroll gesture. The child window should
734   // not receive the touch events.
735   AttemptReveal(MODALITY_GESTURE_SCROLL);
736   EXPECT_TRUE(controller()->IsRevealed());
737   EXPECT_EQ(0, handler.num_touch_events());
738
739   AttemptUnreveal(MODALITY_GESTURE_TAP);
740   EXPECT_FALSE(controller()->IsRevealed());
741   EXPECT_GT(handler.num_touch_events(), 0);
742   child->RemovePreTargetHandler(&handler);
743 }
744
745 // Make sure touch events towards the top of the window do not leak through to
746 // windows underneath.
747 TEST_F(ImmersiveFullscreenControllerTest, EventsDoNotLeakToWindowUnderneath) {
748   gfx::Rect window_bounds = window()->GetBoundsInScreen();
749   aura::test::TestWindowDelegate child_delegate;
750   scoped_ptr<aura::Window> behind(CreateTestWindowInShellWithDelegate(
751       &child_delegate, 1234, window_bounds));
752   behind->Show();
753   behind->SetBounds(window_bounds);
754   widget()->StackAbove(behind.get());
755
756   // Make sure the windows are aligned on top.
757   EXPECT_EQ(behind->GetBoundsInScreen().y(), window()->GetBoundsInScreen().y());
758   int top = behind->GetBoundsInScreen().y();
759
760   ui::TouchEvent touch(ui::ET_TOUCH_MOVED, gfx::Point(10, top), 0,
761                        ui::EventTimeForNow());
762   ui::EventTarget* root = window()->GetRootWindow();
763   ui::EventTargeter* targeter = root->GetEventTargeter();
764   EXPECT_EQ(window(), targeter->FindTargetForEvent(root, &touch));
765
766   SetEnabled(true);
767   EXPECT_FALSE(controller()->IsRevealed());
768   // Make sure the windows are still aligned on top.
769   EXPECT_EQ(behind->GetBoundsInScreen().y(), window()->GetBoundsInScreen().y());
770   top = behind->GetBoundsInScreen().y();
771   ui::TouchEvent touch2(ui::ET_TOUCH_MOVED, gfx::Point(10, top), 0,
772                         ui::EventTimeForNow());
773   // The event should still be targeted to window().
774   EXPECT_EQ(window(), targeter->FindTargetForEvent(root, &touch2));
775 }
776
777 // Check that the window state gets properly marked for immersive fullscreen.
778 TEST_F(ImmersiveFullscreenControllerTest, WindowStateImmersiveFullscreen) {
779   ash::wm::WindowState* window_state = ash::wm::GetWindowState(window());
780
781   EXPECT_FALSE(window_state->in_immersive_fullscreen());
782   SetEnabled(true);
783   ASSERT_TRUE(controller()->IsEnabled());
784   EXPECT_TRUE(window_state->in_immersive_fullscreen());
785
786   SetEnabled(false);
787   ASSERT_FALSE(controller()->IsEnabled());
788   EXPECT_FALSE(window_state->in_immersive_fullscreen());
789 }
790
791 // Do not test under windows because focus testing is not reliable on
792 // Windows. (crbug.com/79493)
793 #if !defined(OS_WIN)
794
795 // Test how focus and activation affects whether the top-of-window views are
796 // revealed.
797 TEST_F(ImmersiveFullscreenControllerTest, Focus) {
798   // Add views to the view hierarchy which we will focus and unfocus during the
799   // test.
800   views::View* child_view = new views::View();
801   child_view->SetBounds(0, 0, 10, 10);
802   child_view->SetFocusable(true);
803   top_container()->AddChildView(child_view);
804   views::View* unrelated_view = new views::View();
805   unrelated_view->SetBounds(0, 100, 10, 10);
806   unrelated_view->SetFocusable(true);
807   top_container()->parent()->AddChildView(unrelated_view);
808   views::FocusManager* focus_manager =
809       top_container()->GetWidget()->GetFocusManager();
810
811   SetEnabled(true);
812
813   // 1) Test that the top-of-window views stay revealed as long as either a
814   // |child_view| has focus or the mouse is hovered above the top-of-window
815   // views.
816   AttemptReveal(MODALITY_MOUSE);
817   child_view->RequestFocus();
818   focus_manager->ClearFocus();
819   EXPECT_TRUE(controller()->IsRevealed());
820   child_view->RequestFocus();
821   SetHovered(false);
822   EXPECT_TRUE(controller()->IsRevealed());
823   focus_manager->ClearFocus();
824   EXPECT_FALSE(controller()->IsRevealed());
825
826   // 2) Test that focusing |unrelated_view| hides the top-of-window views.
827   // Note: In this test we can cheat and trigger a reveal via focus because
828   // the top container does not hide when the top-of-window views are not
829   // revealed.
830   child_view->RequestFocus();
831   EXPECT_TRUE(controller()->IsRevealed());
832   unrelated_view->RequestFocus();
833   EXPECT_FALSE(controller()->IsRevealed());
834
835   // 3) Test that a loss of focus of |child_view| to |unrelated_view|
836   // while immersive mode is disabled is properly registered.
837   child_view->RequestFocus();
838   EXPECT_TRUE(controller()->IsRevealed());
839   SetEnabled(false);
840   EXPECT_FALSE(controller()->IsRevealed());
841   unrelated_view->RequestFocus();
842   SetEnabled(true);
843   EXPECT_FALSE(controller()->IsRevealed());
844
845   // Repeat test but with a revealed lock acquired when immersive mode is
846   // disabled because the code path is different.
847   child_view->RequestFocus();
848   EXPECT_TRUE(controller()->IsRevealed());
849   SetEnabled(false);
850   scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
851       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
852   EXPECT_FALSE(controller()->IsRevealed());
853   unrelated_view->RequestFocus();
854   SetEnabled(true);
855   EXPECT_TRUE(controller()->IsRevealed());
856   lock.reset();
857   EXPECT_FALSE(controller()->IsRevealed());
858 }
859
860 // Test how transient windows affect whether the top-of-window views are
861 // revealed.
862 TEST_F(ImmersiveFullscreenControllerTest, Transient) {
863   views::Widget* top_container_widget = top_container()->GetWidget();
864
865   SetEnabled(true);
866   ASSERT_FALSE(controller()->IsRevealed());
867
868   // 1) Test that a transient window which is not a bubble does not trigger a
869   // reveal but does keep the top-of-window views revealed if they are already
870   // revealed.
871   views::Widget::InitParams transient_params;
872   transient_params.ownership =
873       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
874   transient_params.parent = top_container_widget->GetNativeView();
875   transient_params.bounds = gfx::Rect(0, 100, 100, 100);
876   scoped_ptr<views::Widget> transient_widget(new views::Widget());
877   transient_widget->Init(transient_params);
878
879   EXPECT_FALSE(controller()->IsRevealed());
880   AttemptReveal(MODALITY_MOUSE);
881   EXPECT_TRUE(controller()->IsRevealed());
882   transient_widget->Show();
883   SetHovered(false);
884   EXPECT_TRUE(controller()->IsRevealed());
885   transient_widget.reset();
886   EXPECT_FALSE(controller()->IsRevealed());
887
888   // 2) Test that activating a non-transient window does not keep the
889   // top-of-window views revealed.
890   views::Widget::InitParams non_transient_params;
891   non_transient_params.ownership =
892       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
893   non_transient_params.context = top_container_widget->GetNativeView();
894   non_transient_params.bounds = gfx::Rect(0, 100, 100, 100);
895   scoped_ptr<views::Widget> non_transient_widget(new views::Widget());
896   non_transient_widget->Init(non_transient_params);
897
898   EXPECT_FALSE(controller()->IsRevealed());
899   AttemptReveal(MODALITY_MOUSE);
900   EXPECT_TRUE(controller()->IsRevealed());
901   non_transient_widget->Show();
902   SetHovered(false);
903   EXPECT_FALSE(controller()->IsRevealed());
904 }
905
906 // Test how bubbles affect whether the top-of-window views are revealed.
907 TEST_F(ImmersiveFullscreenControllerTest, Bubbles) {
908   scoped_ptr<ImmersiveRevealedLock> revealed_lock;
909   views::Widget* top_container_widget = top_container()->GetWidget();
910
911   // Add views to the view hierarchy to which we will anchor bubbles.
912   views::View* child_view = new views::View();
913   child_view->SetBounds(0, 0, 10, 10);
914   top_container()->AddChildView(child_view);
915   views::View* unrelated_view = new views::View();
916   unrelated_view->SetBounds(0, 100, 10, 10);
917   top_container()->parent()->AddChildView(unrelated_view);
918
919   SetEnabled(true);
920   ASSERT_FALSE(controller()->IsRevealed());
921
922   // 1) Test that a bubble anchored to a child of the top container triggers
923   // a reveal and keeps the top-of-window views revealed for the duration of
924   // its visibility.
925   views::Widget* bubble_widget1(views::BubbleDelegateView::CreateBubble(
926       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE)));
927   bubble_widget1->Show();
928   EXPECT_TRUE(controller()->IsRevealed());
929
930   // Activating |top_container_widget| will close |bubble_widget1|.
931   top_container_widget->Activate();
932   AttemptReveal(MODALITY_MOUSE);
933   revealed_lock.reset(controller()->GetRevealedLock(
934       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
935   EXPECT_TRUE(controller()->IsRevealed());
936
937   views::Widget* bubble_widget2 = views::BubbleDelegateView::CreateBubble(
938       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
939   bubble_widget2->Show();
940   EXPECT_TRUE(controller()->IsRevealed());
941   revealed_lock.reset();
942   SetHovered(false);
943   EXPECT_TRUE(controller()->IsRevealed());
944   bubble_widget2->Close();
945   EXPECT_FALSE(controller()->IsRevealed());
946
947   // 2) Test that transitioning from keeping the top-of-window views revealed
948   // because of a bubble to keeping the top-of-window views revealed because of
949   // mouse hover by activating |top_container_widget| works.
950   views::Widget* bubble_widget3 = views::BubbleDelegateView::CreateBubble(
951       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
952   bubble_widget3->Show();
953   SetHovered(true);
954   EXPECT_TRUE(controller()->IsRevealed());
955   top_container_widget->Activate();
956   EXPECT_TRUE(controller()->IsRevealed());
957
958   // 3) Test that the top-of-window views stay revealed as long as at least one
959   // bubble anchored to a child of the top container is visible.
960   SetHovered(false);
961   EXPECT_FALSE(controller()->IsRevealed());
962
963   views::BubbleDelegateView* bubble_delegate4(new views::BubbleDelegateView(
964       child_view, views::BubbleBorder::NONE));
965   bubble_delegate4->set_can_activate(false);
966   views::Widget* bubble_widget4(views::BubbleDelegateView::CreateBubble(
967       bubble_delegate4));
968   bubble_widget4->Show();
969
970   views::BubbleDelegateView* bubble_delegate5(new views::BubbleDelegateView(
971       child_view, views::BubbleBorder::NONE));
972   bubble_delegate5->set_can_activate(false);
973   views::Widget* bubble_widget5(views::BubbleDelegateView::CreateBubble(
974       bubble_delegate5));
975   bubble_widget5->Show();
976
977   EXPECT_TRUE(controller()->IsRevealed());
978   bubble_widget4->Hide();
979   EXPECT_TRUE(controller()->IsRevealed());
980   bubble_widget5->Hide();
981   EXPECT_FALSE(controller()->IsRevealed());
982   bubble_widget5->Show();
983   EXPECT_TRUE(controller()->IsRevealed());
984
985   // 4) Test that visibility changes which occur while immersive fullscreen is
986   // disabled are handled upon reenabling immersive fullscreen.
987   SetEnabled(false);
988   bubble_widget5->Hide();
989   SetEnabled(true);
990   EXPECT_FALSE(controller()->IsRevealed());
991
992   // We do not need |bubble_widget4| or |bubble_widget5| anymore, close them.
993   bubble_widget4->Close();
994   bubble_widget5->Close();
995
996   // 5) Test that a bubble added while immersive fullscreen is disabled is
997   // handled upon reenabling immersive fullscreen.
998   SetEnabled(false);
999
1000   views::Widget* bubble_widget6 = views::BubbleDelegateView::CreateBubble(
1001       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
1002   bubble_widget6->Show();
1003
1004   SetEnabled(true);
1005   EXPECT_TRUE(controller()->IsRevealed());
1006
1007   bubble_widget6->Close();
1008
1009   // 6) Test that a bubble which is not anchored to a child of the
1010   // TopContainerView does not trigger a reveal or keep the
1011   // top-of-window views revealed if they are already revealed.
1012   views::Widget* bubble_widget7 = views::BubbleDelegateView::CreateBubble(
1013       new views::BubbleDelegateView(unrelated_view, views::BubbleBorder::NONE));
1014   bubble_widget7->Show();
1015   EXPECT_FALSE(controller()->IsRevealed());
1016
1017   // Activating |top_container_widget| will close |bubble_widget6|.
1018   top_container_widget->Activate();
1019   AttemptReveal(MODALITY_MOUSE);
1020   EXPECT_TRUE(controller()->IsRevealed());
1021
1022   views::Widget* bubble_widget8 = views::BubbleDelegateView::CreateBubble(
1023       new views::BubbleDelegateView(unrelated_view, views::BubbleBorder::NONE));
1024   bubble_widget8->Show();
1025   SetHovered(false);
1026   EXPECT_FALSE(controller()->IsRevealed());
1027   bubble_widget8->Close();
1028 }
1029
1030 #endif  // defined(OS_WIN)
1031
1032 // Test that the shelf is set to auto hide as long as the window is in
1033 // immersive fullscreen and that the shelf's state before entering immersive
1034 // fullscreen is restored upon exiting immersive fullscreen.
1035 TEST_F(ImmersiveFullscreenControllerTest, Shelf) {
1036   ash::ShelfLayoutManager* shelf =
1037       ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
1038
1039   // Shelf is visible by default.
1040   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
1041   ASSERT_FALSE(controller()->IsEnabled());
1042   ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
1043
1044   // Entering immersive fullscreen sets the shelf to auto hide.
1045   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
1046   SetEnabled(true);
1047   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1048
1049   // Disabling immersive fullscreen puts it back.
1050   SetEnabled(false);
1051   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
1052   ASSERT_FALSE(controller()->IsEnabled());
1053   EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
1054
1055   // The user could toggle the shelf auto-hide behavior.
1056   shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
1057   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1058
1059   // Entering immersive fullscreen keeps auto-hide.
1060   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
1061   SetEnabled(true);
1062   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1063
1064   // Disabling immersive fullscreen maintains the user's auto-hide selection.
1065   SetEnabled(false);
1066   window()->SetProperty(aura::client::kShowStateKey,
1067                         ui::SHOW_STATE_NORMAL);
1068   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1069 }
1070
1071 }  // namespase ash