blob: 96391a1c4653967fae5175237be63a60d275ed9d [file] [log] [blame]
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001// 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"
Torne (Richard Coles)cedac222014-06-03 10:58:34 +01008#include "ash/display/mouse_cursor_event_filter.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00009#include "ash/root_window_controller.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000010#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"
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +010014#include "ash/wm/window_state.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000015#include "ui/aura/client/aura_constants.h"
16#include "ui/aura/client/cursor_client.h"
17#include "ui/aura/env.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000018#include "ui/aura/test/event_generator.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000019#include "ui/aura/test/test_window_delegate.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000020#include "ui/aura/window.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000021#include "ui/aura/window_event_dispatcher.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000022#include "ui/events/event_utils.h"
Torne (Richard Coles)23730a62014-03-21 14:25:57 +000023#include "ui/events/test/test_event_handler.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000024#include "ui/gfx/animation/slide_animation.h"
25#include "ui/views/bubble/bubble_delegate.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000026#include "ui/views/controls/native/native_view_host.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000027#include "ui/views/view.h"
28#include "ui/views/widget/widget.h"
29
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000030namespace ash {
31
32namespace {
33
34class 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
Torne (Richard Coles)23730a62014-03-21 14:25:57 +000081class ConsumeEventHandler : public ui::test::TestEventHandler {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000082 public:
83 ConsumeEventHandler() {}
84 virtual ~ConsumeEventHandler() {}
85
86 private:
87 virtual void OnEvent(ui::Event* event) OVERRIDE {
Torne (Richard Coles)23730a62014-03-21 14:25:57 +000088 ui::test::TestEventHandler::OnEvent(event);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000089 if (event->cancelable())
90 event->SetHandled();
91 }
92
93 DISALLOW_COPY_AND_ASSIGN(ConsumeEventHandler);
94};
95
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000096} // namespace
97
98/////////////////////////////////////////////////////////////////////////////
99
100class ImmersiveFullscreenControllerTest : public ash::test::AshTestBase {
101 public:
102 enum Modality {
103 MODALITY_MOUSE,
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000104 MODALITY_GESTURE_TAP,
105 MODALITY_GESTURE_SCROLL
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000106 };
107
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000108 ImmersiveFullscreenControllerTest()
109 : widget_(NULL),
110 top_container_(NULL),
111 content_view_(NULL) {}
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000112 virtual ~ImmersiveFullscreenControllerTest() {}
113
114 ImmersiveFullscreenController* controller() {
115 return controller_.get();
116 }
117
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000118 views::NativeViewHost* content_view() {
119 return content_view_;
120 }
121
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000122 views::View* top_container() {
123 return top_container_;
124 }
125
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000126 views::Widget* widget() { return widget_; }
127
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000128 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
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000157 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
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000162 top_container_ = new views::View();
163 top_container_->SetBounds(
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000164 0, 0, window_size.width(), 100);
165 top_container_->SetFocusable(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000166 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_);
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000172 controller_->SetupForTest();
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000173
174 // The mouse is moved so that it is not over |top_container_| by
175 // AshTestBase.
176 }
177
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000178 // Enables / disables immersive fullscreen.
179 void SetEnabled(bool enabled) {
180 controller_->SetEnabled(ImmersiveFullscreenController::WINDOW_TYPE_OTHER,
181 enabled);
182 }
183
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000184 // 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) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000187 ASSERT_NE(modality, MODALITY_GESTURE_TAP);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000188 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 }
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000231 case MODALITY_GESTURE_TAP: {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000232 gfx::Point screen_position = event_position;
233 views::View::ConvertPointToScreen(top_container_, &screen_position);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000234 aura::test::EventGenerator& event_generator(GetEventGenerator());
235 event_generator.MoveTouch(event_position);
236 event_generator.PressTouch();
237 event_generator.ReleaseTouch();
238 break;
239 }
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000240 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 aura::test::EventGenerator& event_generator(GetEventGenerator());
247 event_generator.GestureScrollSequence(
248 start, end,
249 base::TimeDelta::FromMilliseconds(30), 1);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000250 break;
251 }
252 }
253 }
254
255 scoped_ptr<ImmersiveFullscreenController> controller_;
256 scoped_ptr<MockImmersiveFullscreenControllerDelegate> delegate_;
257 views::Widget* widget_; // Owned by the native widget.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000258 views::View* top_container_; // Owned by |widget_|'s root-view.
259 views::NativeViewHost* content_view_; // Owned by |widget_|'s root-view.
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000260
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.
266TEST_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.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000273 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000274 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.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000287 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000288 EXPECT_FALSE(controller()->IsEnabled());
289 EXPECT_FALSE(controller()->IsRevealed());
290 EXPECT_FALSE(delegate()->is_enabled());
291}
292
293// GetRevealedLock() specific tests.
294TEST_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.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000310 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000311 EXPECT_TRUE(controller()->IsEnabled());
312 EXPECT_TRUE(controller()->IsRevealed());
313
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000314 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000315 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.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000324 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000325 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.
346TEST_F(ImmersiveFullscreenControllerTest, OnMouseEvent) {
347 // Set up initial state.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000348 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000349 ASSERT_TRUE(controller()->IsEnabled());
350 ASSERT_FALSE(controller()->IsRevealed());
351
352 aura::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(
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000362 ui::ET_MOUSEWHEEL, top_edge_pos, top_edge_pos, ui::EF_NONE, ui::EF_NONE);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000363 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.
Ben Murdocha02191e2014-04-16 11:17:03 +0100374 event_generator.MoveMouseBy(0,
375 ImmersiveFullscreenController::kMouseRevealBoundsHeight);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000376 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
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000422 // The mouse position cannot cause a reveal when the top container's widget
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000423 // 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
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000430 // The mouse position cannot end the reveal while the top container's widget
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000431 // 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
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000444// Test mouse event processing for top-of-screen reveal triggering when the
445// top container's widget is inactive.
446TEST_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
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000455 SetEnabled(true);
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000456 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
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000502// 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.
505TEST_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
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000515 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000516 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 aura::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());
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100545
546 // TODO(oshima): Provide a test API to handle mouse warp more easily.
547 if (!MouseCursorEventFilter::IsMouseWarpInNativeCoordsEnabled()) {
548 EXPECT_NE(y_top_edge,
549 aura::Env::GetInstance()->last_mouse_location().y());
550 }
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000551
552 // The timer should continue running if the user overshoots the top edge
553 // a bit.
554 event_generator.MoveMouseTo(x, y_top_edge - 2);
555 EXPECT_TRUE(top_edge_hover_timer_running());
556
557 // The timer should stop running if the user overshoots the top edge by
558 // a lot.
559 event_generator.MoveMouseTo(x, y_top_edge - 20);
560 EXPECT_FALSE(top_edge_hover_timer_running());
561
562 // The timer should not start if the user moves the mouse to the bottom of the
563 // secondary display without crossing the top edge first.
564 event_generator.MoveMouseTo(x, y_top_edge - 2);
565
566 // Reveal the top-of-window views by overshooting the top edge slightly.
567 event_generator.MoveMouseTo(x, y_top_edge + 1);
568 // MoveMouse() runs the timer task.
569 MoveMouse(x, y_top_edge - 2);
570 EXPECT_TRUE(controller()->IsRevealed());
571
572 // The top-of-window views should stay revealed if the user moves the mouse
573 // around in the bottom region of the secondary display.
574 event_generator.MoveMouseTo(x + 10, y_top_edge - 3);
575 EXPECT_TRUE(controller()->IsRevealed());
576
577 // The top-of-window views should hide if the user moves the mouse away from
578 // the bottom region of the secondary display.
579 event_generator.MoveMouseTo(x, y_top_edge - 20);
580 EXPECT_FALSE(controller()->IsRevealed());
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000581
582 // Test that it is possible to reveal the top-of-window views by overshooting
583 // the top edge slightly when the top container's widget is not active.
584 views::Widget* popup_widget = views::Widget::CreateWindowWithContextAndBounds(
585 NULL,
586 CurrentContext(),
587 gfx::Rect(0, 200, 100, 100));
588 popup_widget->Show();
589 ASSERT_FALSE(top_container()->GetWidget()->IsActive());
590 ASSERT_FALSE(top_container()->GetBoundsInScreen().Intersects(
591 popup_widget->GetWindowBoundsInScreen()));
592 event_generator.MoveMouseTo(x, y_top_edge + 1);
593 MoveMouse(x, y_top_edge - 2);
594 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000595}
596
597// Test behavior when the mouse becomes hovered without moving.
598TEST_F(ImmersiveFullscreenControllerTest, MouseHoveredWithoutMoving) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000599 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000600 scoped_ptr<ImmersiveRevealedLock> lock;
601
602 // 1) Test that if the mouse becomes hovered without the mouse moving due to a
603 // lock causing the top-of-window views to be revealed (and the mouse
604 // happening to be near the top of the screen), the top-of-window views do not
605 // hide till the mouse moves off of the top-of-window views.
606 SetHovered(true);
607 EXPECT_FALSE(controller()->IsRevealed());
608 lock.reset(controller()->GetRevealedLock(
609 ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
610 EXPECT_TRUE(controller()->IsRevealed());
611 lock.reset();
612 EXPECT_TRUE(controller()->IsRevealed());
613 SetHovered(false);
614 EXPECT_FALSE(controller()->IsRevealed());
615
616 // 2) Test that if the mouse becomes hovered without moving because of a
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000617 // reveal in ImmersiveFullscreenController::SetEnabled(true) and there are no
618 // locks keeping the top-of-window views revealed, that mouse hover does not
619 // prevent the top-of-window views from closing.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000620 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000621 SetHovered(true);
622 EXPECT_FALSE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000623 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000624 EXPECT_FALSE(controller()->IsRevealed());
625
626 // 3) Test that if the mouse becomes hovered without moving because of a
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000627 // reveal in ImmersiveFullscreenController::SetEnabled(true) and there is a
628 // lock keeping the top-of-window views revealed, that the top-of-window views
629 // do not hide till the mouse moves off of the top-of-window views.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000630 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000631 SetHovered(true);
632 lock.reset(controller()->GetRevealedLock(
633 ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
634 EXPECT_FALSE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000635 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000636 EXPECT_TRUE(controller()->IsRevealed());
637 lock.reset();
638 EXPECT_TRUE(controller()->IsRevealed());
639 SetHovered(false);
640 EXPECT_FALSE(controller()->IsRevealed());
641}
642
643// Test revealing the top-of-window views using one modality and ending
644// the reveal via another. For instance, initiating the reveal via a SWIPE_OPEN
645// edge gesture, switching to using the mouse and ending the reveal by moving
646// the mouse off of the top-of-window views.
647TEST_F(ImmersiveFullscreenControllerTest, DifferentModalityEnterExit) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000648 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000649 EXPECT_TRUE(controller()->IsEnabled());
650 EXPECT_FALSE(controller()->IsRevealed());
651
652 // Initiate reveal via gesture, end reveal via mouse.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000653 AttemptReveal(MODALITY_GESTURE_SCROLL);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000654 EXPECT_TRUE(controller()->IsRevealed());
655 MoveMouse(1, 1);
656 EXPECT_TRUE(controller()->IsRevealed());
657 AttemptUnreveal(MODALITY_MOUSE);
658 EXPECT_FALSE(controller()->IsRevealed());
659
660 // Initiate reveal via gesture, end reveal via touch.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000661 AttemptReveal(MODALITY_GESTURE_SCROLL);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000662 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000663 AttemptUnreveal(MODALITY_GESTURE_TAP);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000664 EXPECT_FALSE(controller()->IsRevealed());
665
666 // Initiate reveal via mouse, end reveal via gesture.
667 AttemptReveal(MODALITY_MOUSE);
668 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000669 AttemptUnreveal(MODALITY_GESTURE_SCROLL);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000670 EXPECT_FALSE(controller()->IsRevealed());
671
672 // Initiate reveal via mouse, end reveal via touch.
673 AttemptReveal(MODALITY_MOUSE);
674 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000675 AttemptUnreveal(MODALITY_GESTURE_TAP);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000676 EXPECT_FALSE(controller()->IsRevealed());
677}
678
679// Test when the SWIPE_CLOSE edge gesture closes the top-of-window views.
Ben Murdocha02191e2014-04-16 11:17:03 +0100680#if defined(OS_WIN)
681// On Windows, touch events do not result in mouse events being disabled. As
682// a result, the last part of this test which ends the reveal via a gesture will
683// not work correctly. See crbug.com/332430, and the function
684// ShouldHideCursorOnTouch() in compound_event_filter.cc.
685#define MAYBE_EndRevealViaGesture DISABLED_EndRevealViaGesture
686#else
687#define MAYBE_EndRevealViaGesture EndRevealViaGesture
688#endif
689TEST_F(ImmersiveFullscreenControllerTest, MAYBE_EndRevealViaGesture) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000690 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000691 EXPECT_TRUE(controller()->IsEnabled());
692 EXPECT_FALSE(controller()->IsRevealed());
693
694 // A gesture should be able to close the top-of-window views when
695 // top-of-window views have focus.
696 AttemptReveal(MODALITY_MOUSE);
697 top_container()->RequestFocus();
698 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000699 AttemptUnreveal(MODALITY_GESTURE_SCROLL);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000700 EXPECT_FALSE(controller()->IsRevealed());
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000701
702 // The top-of-window views should no longer have focus. Clearing focus is
703 // important because it closes focus-related popup windows like the touch
704 // selection handles.
705 EXPECT_FALSE(top_container()->HasFocus());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000706
707 // If some other code is holding onto a lock, a gesture should not be able to
708 // end the reveal.
709 AttemptReveal(MODALITY_MOUSE);
710 scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
711 ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
712 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000713 AttemptUnreveal(MODALITY_GESTURE_SCROLL);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000714 EXPECT_TRUE(controller()->IsRevealed());
715 lock.reset();
716 EXPECT_FALSE(controller()->IsRevealed());
717}
718
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000719// Tests that touch-gesture can be used to reveal the top-of-window views when
720// the child window consumes all events.
721TEST_F(ImmersiveFullscreenControllerTest, RevealViaGestureChildConsumesEvents) {
722 // Enabling initially hides the top views.
723 SetEnabled(true);
724 EXPECT_TRUE(controller()->IsEnabled());
725 EXPECT_FALSE(controller()->IsRevealed());
726
727 aura::test::TestWindowDelegate child_delegate;
728 scoped_ptr<aura::Window> child(
729 CreateTestWindowInShellWithDelegateAndType(&child_delegate,
730 ui::wm::WINDOW_TYPE_CONTROL,
731 1234,
732 gfx::Rect()));
733 content_view()->Attach(child.get());
734 child->Show();
735
736 ConsumeEventHandler handler;
737 child->AddPreTargetHandler(&handler);
738
739 // Reveal the top views using a touch-scroll gesture. The child window should
740 // not receive the touch events.
741 AttemptReveal(MODALITY_GESTURE_SCROLL);
742 EXPECT_TRUE(controller()->IsRevealed());
743 EXPECT_EQ(0, handler.num_touch_events());
744
745 AttemptUnreveal(MODALITY_GESTURE_TAP);
746 EXPECT_FALSE(controller()->IsRevealed());
747 EXPECT_GT(handler.num_touch_events(), 0);
748 child->RemovePreTargetHandler(&handler);
749}
750
751// Make sure touch events towards the top of the window do not leak through to
752// windows underneath.
753TEST_F(ImmersiveFullscreenControllerTest, EventsDoNotLeakToWindowUnderneath) {
754 gfx::Rect window_bounds = window()->GetBoundsInScreen();
755 aura::test::TestWindowDelegate child_delegate;
756 scoped_ptr<aura::Window> behind(CreateTestWindowInShellWithDelegate(
757 &child_delegate, 1234, window_bounds));
758 behind->Show();
759 behind->SetBounds(window_bounds);
760 widget()->StackAbove(behind.get());
761
762 // Make sure the windows are aligned on top.
763 EXPECT_EQ(behind->GetBoundsInScreen().y(), window()->GetBoundsInScreen().y());
764 int top = behind->GetBoundsInScreen().y();
765
766 ui::TouchEvent touch(ui::ET_TOUCH_MOVED, gfx::Point(10, top), 0,
767 ui::EventTimeForNow());
768 ui::EventTarget* root = window()->GetRootWindow();
769 ui::EventTargeter* targeter = root->GetEventTargeter();
770 EXPECT_EQ(window(), targeter->FindTargetForEvent(root, &touch));
771
772 SetEnabled(true);
773 EXPECT_FALSE(controller()->IsRevealed());
774 // Make sure the windows are still aligned on top.
775 EXPECT_EQ(behind->GetBoundsInScreen().y(), window()->GetBoundsInScreen().y());
776 top = behind->GetBoundsInScreen().y();
777 ui::TouchEvent touch2(ui::ET_TOUCH_MOVED, gfx::Point(10, top), 0,
778 ui::EventTimeForNow());
779 // The event should still be targeted to window().
780 EXPECT_EQ(window(), targeter->FindTargetForEvent(root, &touch2));
781}
782
Torne (Richard Coles)46d4c2b2014-06-09 12:00:27 +0100783// Check that the window state gets properly marked for immersive fullscreen.
784TEST_F(ImmersiveFullscreenControllerTest, WindowStateImmersiveFullscreen) {
785 ash::wm::WindowState* window_state = ash::wm::GetWindowState(window());
786
787 EXPECT_FALSE(window_state->in_immersive_fullscreen());
788 SetEnabled(true);
789 ASSERT_TRUE(controller()->IsEnabled());
790 EXPECT_TRUE(window_state->in_immersive_fullscreen());
791
792 SetEnabled(false);
793 ASSERT_FALSE(controller()->IsEnabled());
794 EXPECT_FALSE(window_state->in_immersive_fullscreen());
795}
796
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000797// Do not test under windows because focus testing is not reliable on
798// Windows. (crbug.com/79493)
799#if !defined(OS_WIN)
800
801// Test how focus and activation affects whether the top-of-window views are
802// revealed.
803TEST_F(ImmersiveFullscreenControllerTest, Focus) {
804 // Add views to the view hierarchy which we will focus and unfocus during the
805 // test.
806 views::View* child_view = new views::View();
807 child_view->SetBounds(0, 0, 10, 10);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000808 child_view->SetFocusable(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000809 top_container()->AddChildView(child_view);
810 views::View* unrelated_view = new views::View();
811 unrelated_view->SetBounds(0, 100, 10, 10);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000812 unrelated_view->SetFocusable(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000813 top_container()->parent()->AddChildView(unrelated_view);
814 views::FocusManager* focus_manager =
815 top_container()->GetWidget()->GetFocusManager();
816
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000817 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000818
819 // 1) Test that the top-of-window views stay revealed as long as either a
820 // |child_view| has focus or the mouse is hovered above the top-of-window
821 // views.
822 AttemptReveal(MODALITY_MOUSE);
823 child_view->RequestFocus();
824 focus_manager->ClearFocus();
825 EXPECT_TRUE(controller()->IsRevealed());
826 child_view->RequestFocus();
827 SetHovered(false);
828 EXPECT_TRUE(controller()->IsRevealed());
829 focus_manager->ClearFocus();
830 EXPECT_FALSE(controller()->IsRevealed());
831
832 // 2) Test that focusing |unrelated_view| hides the top-of-window views.
833 // Note: In this test we can cheat and trigger a reveal via focus because
834 // the top container does not hide when the top-of-window views are not
835 // revealed.
836 child_view->RequestFocus();
837 EXPECT_TRUE(controller()->IsRevealed());
838 unrelated_view->RequestFocus();
839 EXPECT_FALSE(controller()->IsRevealed());
840
841 // 3) Test that a loss of focus of |child_view| to |unrelated_view|
842 // while immersive mode is disabled is properly registered.
843 child_view->RequestFocus();
844 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000845 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000846 EXPECT_FALSE(controller()->IsRevealed());
847 unrelated_view->RequestFocus();
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000848 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000849 EXPECT_FALSE(controller()->IsRevealed());
850
851 // Repeat test but with a revealed lock acquired when immersive mode is
852 // disabled because the code path is different.
853 child_view->RequestFocus();
854 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000855 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000856 scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
857 ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
858 EXPECT_FALSE(controller()->IsRevealed());
859 unrelated_view->RequestFocus();
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000860 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000861 EXPECT_TRUE(controller()->IsRevealed());
862 lock.reset();
863 EXPECT_FALSE(controller()->IsRevealed());
864}
865
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000866// Test how transient windows affect whether the top-of-window views are
867// revealed.
868TEST_F(ImmersiveFullscreenControllerTest, Transient) {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000869 views::Widget* top_container_widget = top_container()->GetWidget();
870
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000871 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000872 ASSERT_FALSE(controller()->IsRevealed());
873
874 // 1) Test that a transient window which is not a bubble does not trigger a
875 // reveal but does keep the top-of-window views revealed if they are already
876 // revealed.
877 views::Widget::InitParams transient_params;
878 transient_params.ownership =
879 views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
880 transient_params.parent = top_container_widget->GetNativeView();
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000881 transient_params.bounds = gfx::Rect(0, 100, 100, 100);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000882 scoped_ptr<views::Widget> transient_widget(new views::Widget());
883 transient_widget->Init(transient_params);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000884
885 EXPECT_FALSE(controller()->IsRevealed());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000886 AttemptReveal(MODALITY_MOUSE);
887 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000888 transient_widget->Show();
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000889 SetHovered(false);
890 EXPECT_TRUE(controller()->IsRevealed());
891 transient_widget.reset();
892 EXPECT_FALSE(controller()->IsRevealed());
893
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000894 // 2) Test that activating a non-transient window does not keep the
895 // top-of-window views revealed.
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000896 views::Widget::InitParams non_transient_params;
897 non_transient_params.ownership =
898 views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
899 non_transient_params.context = top_container_widget->GetNativeView();
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000900 non_transient_params.bounds = gfx::Rect(0, 100, 100, 100);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000901 scoped_ptr<views::Widget> non_transient_widget(new views::Widget());
902 non_transient_widget->Init(non_transient_params);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000903
904 EXPECT_FALSE(controller()->IsRevealed());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000905 AttemptReveal(MODALITY_MOUSE);
906 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000907 non_transient_widget->Show();
908 SetHovered(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000909 EXPECT_FALSE(controller()->IsRevealed());
910}
911
912// Test how bubbles affect whether the top-of-window views are revealed.
913TEST_F(ImmersiveFullscreenControllerTest, Bubbles) {
914 scoped_ptr<ImmersiveRevealedLock> revealed_lock;
915 views::Widget* top_container_widget = top_container()->GetWidget();
916
917 // Add views to the view hierarchy to which we will anchor bubbles.
918 views::View* child_view = new views::View();
919 child_view->SetBounds(0, 0, 10, 10);
920 top_container()->AddChildView(child_view);
921 views::View* unrelated_view = new views::View();
922 unrelated_view->SetBounds(0, 100, 10, 10);
923 top_container()->parent()->AddChildView(unrelated_view);
924
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000925 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000926 ASSERT_FALSE(controller()->IsRevealed());
927
928 // 1) Test that a bubble anchored to a child of the top container triggers
929 // a reveal and keeps the top-of-window views revealed for the duration of
930 // its visibility.
931 views::Widget* bubble_widget1(views::BubbleDelegateView::CreateBubble(
932 new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE)));
933 bubble_widget1->Show();
934 EXPECT_TRUE(controller()->IsRevealed());
935
936 // Activating |top_container_widget| will close |bubble_widget1|.
937 top_container_widget->Activate();
938 AttemptReveal(MODALITY_MOUSE);
939 revealed_lock.reset(controller()->GetRevealedLock(
940 ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
941 EXPECT_TRUE(controller()->IsRevealed());
942
943 views::Widget* bubble_widget2 = views::BubbleDelegateView::CreateBubble(
944 new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
945 bubble_widget2->Show();
946 EXPECT_TRUE(controller()->IsRevealed());
947 revealed_lock.reset();
948 SetHovered(false);
949 EXPECT_TRUE(controller()->IsRevealed());
950 bubble_widget2->Close();
951 EXPECT_FALSE(controller()->IsRevealed());
952
953 // 2) Test that transitioning from keeping the top-of-window views revealed
954 // because of a bubble to keeping the top-of-window views revealed because of
955 // mouse hover by activating |top_container_widget| works.
956 views::Widget* bubble_widget3 = views::BubbleDelegateView::CreateBubble(
957 new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
958 bubble_widget3->Show();
959 SetHovered(true);
960 EXPECT_TRUE(controller()->IsRevealed());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000961 top_container_widget->Activate();
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000962 EXPECT_TRUE(controller()->IsRevealed());
963
964 // 3) Test that the top-of-window views stay revealed as long as at least one
965 // bubble anchored to a child of the top container is visible.
966 SetHovered(false);
967 EXPECT_FALSE(controller()->IsRevealed());
968
969 views::BubbleDelegateView* bubble_delegate4(new views::BubbleDelegateView(
970 child_view, views::BubbleBorder::NONE));
971 bubble_delegate4->set_use_focusless(true);
972 views::Widget* bubble_widget4(views::BubbleDelegateView::CreateBubble(
973 bubble_delegate4));
974 bubble_widget4->Show();
975
976 views::BubbleDelegateView* bubble_delegate5(new views::BubbleDelegateView(
977 child_view, views::BubbleBorder::NONE));
978 bubble_delegate5->set_use_focusless(true);
979 views::Widget* bubble_widget5(views::BubbleDelegateView::CreateBubble(
980 bubble_delegate5));
981 bubble_widget5->Show();
982
983 EXPECT_TRUE(controller()->IsRevealed());
984 bubble_widget4->Hide();
985 EXPECT_TRUE(controller()->IsRevealed());
986 bubble_widget5->Hide();
987 EXPECT_FALSE(controller()->IsRevealed());
988 bubble_widget5->Show();
989 EXPECT_TRUE(controller()->IsRevealed());
990
991 // 4) Test that visibility changes which occur while immersive fullscreen is
992 // disabled are handled upon reenabling immersive fullscreen.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000993 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000994 bubble_widget5->Hide();
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000995 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000996 EXPECT_FALSE(controller()->IsRevealed());
997
998 // We do not need |bubble_widget4| or |bubble_widget5| anymore, close them.
999 bubble_widget4->Close();
1000 bubble_widget5->Close();
1001
1002 // 5) Test that a bubble added while immersive fullscreen is disabled is
1003 // handled upon reenabling immersive fullscreen.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +00001004 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001005
1006 views::Widget* bubble_widget6 = views::BubbleDelegateView::CreateBubble(
1007 new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
1008 bubble_widget6->Show();
1009
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +00001010 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001011 EXPECT_TRUE(controller()->IsRevealed());
1012
1013 bubble_widget6->Close();
1014
1015 // 6) Test that a bubble which is not anchored to a child of the
1016 // TopContainerView does not trigger a reveal or keep the
1017 // top-of-window views revealed if they are already revealed.
1018 views::Widget* bubble_widget7 = views::BubbleDelegateView::CreateBubble(
1019 new views::BubbleDelegateView(unrelated_view, views::BubbleBorder::NONE));
1020 bubble_widget7->Show();
1021 EXPECT_FALSE(controller()->IsRevealed());
1022
1023 // Activating |top_container_widget| will close |bubble_widget6|.
1024 top_container_widget->Activate();
1025 AttemptReveal(MODALITY_MOUSE);
1026 EXPECT_TRUE(controller()->IsRevealed());
1027
1028 views::Widget* bubble_widget8 = views::BubbleDelegateView::CreateBubble(
1029 new views::BubbleDelegateView(unrelated_view, views::BubbleBorder::NONE));
1030 bubble_widget8->Show();
1031 SetHovered(false);
1032 EXPECT_FALSE(controller()->IsRevealed());
1033 bubble_widget8->Close();
1034}
1035
1036#endif // defined(OS_WIN)
1037
1038// Test that the shelf is set to auto hide as long as the window is in
1039// immersive fullscreen and that the shelf's state before entering immersive
1040// fullscreen is restored upon exiting immersive fullscreen.
1041TEST_F(ImmersiveFullscreenControllerTest, Shelf) {
Ben Murdochc5cede92014-04-10 11:22:14 +01001042 ash::ShelfLayoutManager* shelf =
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001043 ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
1044
1045 // Shelf is visible by default.
1046 window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
1047 ASSERT_FALSE(controller()->IsEnabled());
1048 ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
1049
1050 // Entering immersive fullscreen sets the shelf to auto hide.
1051 window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +00001052 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001053 EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1054
1055 // Disabling immersive fullscreen puts it back.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +00001056 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001057 window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
1058 ASSERT_FALSE(controller()->IsEnabled());
1059 EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
1060
1061 // The user could toggle the shelf auto-hide behavior.
1062 shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
1063 EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1064
1065 // Entering immersive fullscreen keeps auto-hide.
1066 window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +00001067 SetEnabled(true);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001068 EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1069
1070 // Disabling immersive fullscreen maintains the user's auto-hide selection.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +00001071 SetEnabled(false);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +00001072 window()->SetProperty(aura::client::kShowStateKey,
1073 ui::SHOW_STATE_NORMAL);
1074 EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
1075}
1076
1077} // namespase ash