chromium/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler_unittest.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.h"

#include "ash/test/ash_test_base.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/wm/tablet_mode/tablet_mode_multitask_menu_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.h"
#include "chromeos/ui/base/window_properties.h"
#include "ui/aura/window.h"

namespace ash {

class TabletModeToggleFullscreenEventHandlerTest : public AshTestBase {
 public:
  TabletModeToggleFullscreenEventHandlerTest() = default;
  TabletModeToggleFullscreenEventHandlerTest(
      const TabletModeToggleFullscreenEventHandlerTest&) = delete;
  TabletModeToggleFullscreenEventHandlerTest& operator=(
      const TabletModeToggleFullscreenEventHandlerTest&) = delete;
  ~TabletModeToggleFullscreenEventHandlerTest() override = default;

  // AshTestBase:
  void SetUp() override {
    AshTestBase::SetUp();

    UpdateDisplay("800x600");
    TabletModeControllerTestApi().EnterTabletMode();

    background_window_ = CreateTestWindow(gfx::Rect(200, 200));
    foreground_window_ = CreateTestWindow(gfx::Rect(200, 200));
    ToggleFullscreen(foreground_window_.get(), /*immersive=*/false);
    ToggleFullscreen(background_window_.get(), /*immersive=*/false);
  }

  void TearDown() override {
    background_window_.reset();
    foreground_window_.reset();
    AshTestBase::TearDown();
  }

  void ToggleFullscreen(aura::Window* window, bool immersive) {
    WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
    WindowState::Get(window)->OnWMEvent(&toggle_fullscreen);
    window->SetProperty(chromeos::kImmersiveIsActive, immersive);
  }

  bool IsFullscreen(aura::Window* window) const {
    return WindowState::Get(window)->IsFullscreen();
  }

  void GenerateSwipe(int start_y, int end_y) {
    GetEventGenerator()->GestureScrollSequence(gfx::Point(100, start_y),
                                               gfx::Point(100, end_y),
                                               base::Milliseconds(100), 3);

    // Swiping down on the center reveals the tablet mode multitask menu. Ensure
    // our swipes do not reveal it, as it may eat following gestures.
    auto* multitask_menu = TabletModeControllerTestApi()
                               .tablet_mode_window_manager()
                               ->tablet_mode_multitask_menu_controller()
                               ->multitask_menu();
    ASSERT_FALSE(multitask_menu);
  }

  aura::Window* foreground_window() { return foreground_window_.get(); }
  aura::Window* background_window() { return background_window_.get(); }

 private:
  std::unique_ptr<aura::Window> foreground_window_;
  std::unique_ptr<aura::Window> background_window_;
};

TEST_F(TabletModeToggleFullscreenEventHandlerTest, SwipeFromTop) {
  ASSERT_TRUE(IsFullscreen(foreground_window()));
  ASSERT_TRUE(IsFullscreen(background_window()));

  // Try swiping from a point not on the edge. Verify that we do not exit
  // fullscreen.
  GenerateSwipe(100, 200);
  ASSERT_TRUE(IsFullscreen(foreground_window()));
  ASSERT_TRUE(IsFullscreen(background_window()));

  // Try a tiny swipe that is on the edge. Verify that we do not exit
  // fullscreen.
  GenerateSwipe(1, 5);
  ASSERT_TRUE(IsFullscreen(foreground_window()));
  ASSERT_TRUE(IsFullscreen(background_window()));

  // Test that a normal swipe on the edge will exit fullscreen on the active
  // window.
  GenerateSwipe(1, 50);
  EXPECT_FALSE(IsFullscreen(foreground_window()));
  EXPECT_TRUE(IsFullscreen(background_window()));

  // Test that a second swipe will not do anything..
  GenerateSwipe(1, 50);
  EXPECT_FALSE(IsFullscreen(foreground_window()));
  EXPECT_TRUE(IsFullscreen(background_window()));
}

TEST_F(TabletModeToggleFullscreenEventHandlerTest, SwipeFromBottom) {
  ASSERT_TRUE(IsFullscreen(foreground_window()));
  ASSERT_TRUE(IsFullscreen(background_window()));

  // Try swiping from a point not on the edge. Verify that we do not exit
  // fullscreen.
  GenerateSwipe(500, 400);
  ASSERT_TRUE(IsFullscreen(foreground_window()));
  ASSERT_TRUE(IsFullscreen(background_window()));

  // Try a tiny swipe that is on the edge. Verify that we do not exit
  // fullscreen.
  GenerateSwipe(599, 594);
  ASSERT_TRUE(IsFullscreen(foreground_window()));
  ASSERT_TRUE(IsFullscreen(background_window()));

  // Test that a normal swipe on the edge will exit fullscreen on the active
  // window.
  GenerateSwipe(599, 549);
  EXPECT_FALSE(IsFullscreen(foreground_window()));
  EXPECT_TRUE(IsFullscreen(background_window()));
}

// Tests that tapping on the edge does not exit fullscreen.
TEST_F(TabletModeToggleFullscreenEventHandlerTest, TapOnEdge) {
  ASSERT_TRUE(IsFullscreen(foreground_window()));

  // Tap on the top edge.
  GetEventGenerator()->set_current_screen_location(gfx::Point(400, 1));
  GetEventGenerator()->PressTouch();
  GetEventGenerator()->ReleaseTouch();
  EXPECT_TRUE(IsFullscreen(foreground_window()));

  // Tap on the bottom edge.
  GetEventGenerator()->set_current_screen_location(gfx::Point(400, 50));
  GetEventGenerator()->PressTouch();
  GetEventGenerator()->ReleaseTouch();
  EXPECT_TRUE(IsFullscreen(foreground_window()));
}

TEST_F(TabletModeToggleFullscreenEventHandlerTest,
       SwipeImmersiveFullscreenWindow) {
  // Switch from non-immersive fullscreen to immersive fullscreen mode.
  ToggleFullscreen(foreground_window(), /*immersive=*/true);
  ToggleFullscreen(foreground_window(), /*immersive=*/true);
  ASSERT_TRUE(IsFullscreen(foreground_window()));

  // Test that a normal swipe on the top edge will not exit immersive
  // fullscreen.
  GenerateSwipe(1, 50);
  EXPECT_TRUE(IsFullscreen(foreground_window()));
  EXPECT_TRUE(IsFullscreen(background_window()));

  // Test that a normal swipe on the top edge will not exit immersive
  // fullscreen.
  GenerateSwipe(599, 549);
  EXPECT_TRUE(IsFullscreen(foreground_window()));
  EXPECT_TRUE(IsFullscreen(background_window()));
}

// Tests that if a window is un-fullscreened during a drag, it remains
// un-fullscreened on touch release.
TEST_F(TabletModeToggleFullscreenEventHandlerTest, ToggleFullscreenDuringDrag) {
  ASSERT_TRUE(IsFullscreen(foreground_window()));

  GetEventGenerator()->set_current_screen_location(gfx::Point(400, 1));
  GetEventGenerator()->PressTouch();
  ToggleFullscreen(foreground_window(), /*immersive=*/false);
  EXPECT_FALSE(IsFullscreen(foreground_window()));

  GetEventGenerator()->set_current_screen_location(gfx::Point(400, 50));
  GetEventGenerator()->ReleaseTouch();
  EXPECT_FALSE(IsFullscreen(foreground_window()));
}

// Tests that we do not have a crash when using this feature with multiple
// fingers. Regression test for b/270155382.
TEST_F(TabletModeToggleFullscreenEventHandlerTest, SwipingWithMultipleFingers) {
  ASSERT_TRUE(IsFullscreen(foreground_window()));

  const int kTouchId1 = 1;
  const int kTouchId2 = 2;

  GetEventGenerator()->PressTouchId(kTouchId1, gfx::Point(400, 1));
  GetEventGenerator()->MoveTouchIdBy(kTouchId1, 0, 48);

  // Swipe with a second finger while the first one is still touching the
  // screen. There should be no crash.
  GetEventGenerator()->PressTouchId(kTouchId2, gfx::Point(400, 1));
  GetEventGenerator()->MoveTouchIdBy(kTouchId2, 0, 48);
  GetEventGenerator()->ReleaseTouchId(kTouchId2);

  // Release the first finger and verify the window is un-fullscreened.
  GetEventGenerator()->ReleaseTouchId(kTouchId1);
  EXPECT_FALSE(IsFullscreen(foreground_window()));
}

}  // namespace ash