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/event_generator.h" 19 #include "ui/aura/test/test_window_delegate.h" 20 #include "ui/aura/window.h" 21 #include "ui/aura/window_event_dispatcher.h" 22 #include "ui/events/event_utils.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 aura::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 aura::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 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( 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 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()); 545 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 } 551 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()); 581 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()); 595 } 596 597 // Test behavior when the mouse becomes hovered without moving. 598 TEST_F(ImmersiveFullscreenControllerTest, MouseHoveredWithoutMoving) { 599 SetEnabled(true); 600 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 617 // 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. 620 SetEnabled(false); 621 SetHovered(true); 622 EXPECT_FALSE(controller()->IsRevealed()); 623 SetEnabled(true); 624 EXPECT_FALSE(controller()->IsRevealed()); 625 626 // 3) Test that if the mouse becomes hovered without moving because of a 627 // 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. 630 SetEnabled(false); 631 SetHovered(true); 632 lock.reset(controller()->GetRevealedLock( 633 ImmersiveFullscreenController::ANIMATE_REVEAL_NO)); 634 EXPECT_FALSE(controller()->IsRevealed()); 635 SetEnabled(true); 636 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. 647 TEST_F(ImmersiveFullscreenControllerTest, DifferentModalityEnterExit) { 648 SetEnabled(true); 649 EXPECT_TRUE(controller()->IsEnabled()); 650 EXPECT_FALSE(controller()->IsRevealed()); 651 652 // Initiate reveal via gesture, end reveal via mouse. 653 AttemptReveal(MODALITY_GESTURE_SCROLL); 654 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. 661 AttemptReveal(MODALITY_GESTURE_SCROLL); 662 EXPECT_TRUE(controller()->IsRevealed()); 663 AttemptUnreveal(MODALITY_GESTURE_TAP); 664 EXPECT_FALSE(controller()->IsRevealed()); 665 666 // Initiate reveal via mouse, end reveal via gesture. 667 AttemptReveal(MODALITY_MOUSE); 668 EXPECT_TRUE(controller()->IsRevealed()); 669 AttemptUnreveal(MODALITY_GESTURE_SCROLL); 670 EXPECT_FALSE(controller()->IsRevealed()); 671 672 // Initiate reveal via mouse, end reveal via touch. 673 AttemptReveal(MODALITY_MOUSE); 674 EXPECT_TRUE(controller()->IsRevealed()); 675 AttemptUnreveal(MODALITY_GESTURE_TAP); 676 EXPECT_FALSE(controller()->IsRevealed()); 677 } 678 679 // Test when the SWIPE_CLOSE edge gesture closes the top-of-window views. 680 #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 689 TEST_F(ImmersiveFullscreenControllerTest, MAYBE_EndRevealViaGesture) { 690 SetEnabled(true); 691 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()); 699 AttemptUnreveal(MODALITY_GESTURE_SCROLL); 700 EXPECT_FALSE(controller()->IsRevealed()); 701 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()); 706 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()); 713 AttemptUnreveal(MODALITY_GESTURE_SCROLL); 714 EXPECT_TRUE(controller()->IsRevealed()); 715 lock.reset(); 716 EXPECT_FALSE(controller()->IsRevealed()); 717 } 718 719 // Tests that touch-gesture can be used to reveal the top-of-window views when 720 // the child window consumes all events. 721 TEST_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. 753 TEST_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 783 // Check that the window state gets properly marked for immersive fullscreen. 784 TEST_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 797 // 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. 803 TEST_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); 808 child_view->SetFocusable(true); 809 top_container()->AddChildView(child_view); 810 views::View* unrelated_view = new views::View(); 811 unrelated_view->SetBounds(0, 100, 10, 10); 812 unrelated_view->SetFocusable(true); 813 top_container()->parent()->AddChildView(unrelated_view); 814 views::FocusManager* focus_manager = 815 top_container()->GetWidget()->GetFocusManager(); 816 817 SetEnabled(true); 818 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()); 845 SetEnabled(false); 846 EXPECT_FALSE(controller()->IsRevealed()); 847 unrelated_view->RequestFocus(); 848 SetEnabled(true); 849 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()); 855 SetEnabled(false); 856 scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock( 857 ImmersiveFullscreenController::ANIMATE_REVEAL_NO)); 858 EXPECT_FALSE(controller()->IsRevealed()); 859 unrelated_view->RequestFocus(); 860 SetEnabled(true); 861 EXPECT_TRUE(controller()->IsRevealed()); 862 lock.reset(); 863 EXPECT_FALSE(controller()->IsRevealed()); 864 } 865 866 // Test how transient windows affect whether the top-of-window views are 867 // revealed. 868 TEST_F(ImmersiveFullscreenControllerTest, Transient) { 869 views::Widget* top_container_widget = top_container()->GetWidget(); 870 871 SetEnabled(true); 872 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(); 881 transient_params.bounds = gfx::Rect(0, 100, 100, 100); 882 scoped_ptr<views::Widget> transient_widget(new views::Widget()); 883 transient_widget->Init(transient_params); 884 885 EXPECT_FALSE(controller()->IsRevealed()); 886 AttemptReveal(MODALITY_MOUSE); 887 EXPECT_TRUE(controller()->IsRevealed()); 888 transient_widget->Show(); 889 SetHovered(false); 890 EXPECT_TRUE(controller()->IsRevealed()); 891 transient_widget.reset(); 892 EXPECT_FALSE(controller()->IsRevealed()); 893 894 // 2) Test that activating a non-transient window does not keep the 895 // top-of-window views revealed. 896 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(); 900 non_transient_params.bounds = gfx::Rect(0, 100, 100, 100); 901 scoped_ptr<views::Widget> non_transient_widget(new views::Widget()); 902 non_transient_widget->Init(non_transient_params); 903 904 EXPECT_FALSE(controller()->IsRevealed()); 905 AttemptReveal(MODALITY_MOUSE); 906 EXPECT_TRUE(controller()->IsRevealed()); 907 non_transient_widget->Show(); 908 SetHovered(false); 909 EXPECT_FALSE(controller()->IsRevealed()); 910 } 911 912 // Test how bubbles affect whether the top-of-window views are revealed. 913 TEST_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 925 SetEnabled(true); 926 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()); 961 top_container_widget->Activate(); 962 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. 993 SetEnabled(false); 994 bubble_widget5->Hide(); 995 SetEnabled(true); 996 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. 1004 SetEnabled(false); 1005 1006 views::Widget* bubble_widget6 = views::BubbleDelegateView::CreateBubble( 1007 new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE)); 1008 bubble_widget6->Show(); 1009 1010 SetEnabled(true); 1011 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. 1041 TEST_F(ImmersiveFullscreenControllerTest, Shelf) { 1042 ash::ShelfLayoutManager* shelf = 1043 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); 1052 SetEnabled(true); 1053 EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state()); 1054 1055 // Disabling immersive fullscreen puts it back. 1056 SetEnabled(false); 1057 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); 1067 SetEnabled(true); 1068 EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state()); 1069 1070 // Disabling immersive fullscreen maintains the user's auto-hide selection. 1071 SetEnabled(false); 1072 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 1078