0

tablet: Change tap on edge to exit non-immersive fullscreen to swipe.

Non-immersive fullscreen mode (i.e. youtube video pressed with
app fullscreen button) is too easy to exit by accident by tapping on
the top/bottom edge. This CL changes that logic to be a swipe instead.

The swipe is same logic as shelf swipe but needs to be started on the
edge. Also moved tests to a new file.

Test: added tests
Bug: 497784
Change-Id: Id197d1109d39d89467d844d8b82c72f9a3547540
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2138552
Reviewed-by: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#757586}
This commit is contained in:
Sammie Quon
2020-04-08 21:26:44 +00:00
committed by Commit Bot
parent 3670919e0c
commit a3fbe4bdcf
12 changed files with 389 additions and 328 deletions

@@ -1366,8 +1366,8 @@ component("ash") {
"wm/tablet_mode/scoped_skip_user_session_blocked_check.h",
"wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc",
"wm/tablet_mode/tablet_mode_controller.cc",
"wm/tablet_mode/tablet_mode_event_handler.cc",
"wm/tablet_mode/tablet_mode_event_handler.h",
"wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.cc",
"wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.h",
"wm/tablet_mode/tablet_mode_window_drag_delegate.cc",
"wm/tablet_mode/tablet_mode_window_drag_metrics.cc",
"wm/tablet_mode/tablet_mode_window_drag_metrics.h",
@@ -2094,6 +2094,7 @@ test("ash_unittests") {
"wm/system_modal_container_layout_manager_unittest.cc",
"wm/tablet_mode/accelerometer_test_data_literals.cc",
"wm/tablet_mode/tablet_mode_controller_unittest.cc",
"wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler_unittest.cc",
"wm/tablet_mode/tablet_mode_window_manager_unittest.cc",
"wm/toplevel_window_event_handler_unittest.cc",
"wm/video_detector_unittest.cc",

@@ -116,6 +116,10 @@ class ASH_EXPORT ShelfConfig : public TabletModeObserver,
// Returns whether we are within an app.
bool is_in_app() const;
// The threshold relative to the size of the shelf that is used to determine
// if the shelf visibility should change during a drag.
float drag_hide_ratio_threshold() const;
int app_icon_group_margin() const { return app_icon_group_margin_; }
SkColor shelf_control_permanent_highlight_background() const {
return shelf_control_permanent_highlight_background_;

@@ -36,7 +36,11 @@ constexpr int kControlButtonsShownReasonCount = 1 << 4;
// When any edge of the primary display is less than or equal to this threshold,
// dense shelf will be active.
const int kDenseShelfScreenSizeThreshold = 600;
constexpr int kDenseShelfScreenSizeThreshold = 600;
// Drags on the shelf that are greater than this number times the shelf size
// will trigger shelf visibility changes.
constexpr float kDragHideRatioThreshold = 0.4f;
// Records the histogram value tracking the reason shelf control buttons are
// shown in tablet mode.
@@ -305,6 +309,10 @@ bool ShelfConfig::is_in_app() const {
(!is_app_list_visible_ || is_virtual_keyboard_shown_);
}
float ShelfConfig::drag_hide_ratio_threshold() const {
return kDragHideRatioThreshold;
}
void ShelfConfig::UpdateConfig(bool app_list_visible) {
const gfx::Rect screen_size =
display::Screen::GetScreen()->GetPrimaryDisplay().bounds();

@@ -2508,13 +2508,13 @@ bool ShelfLayoutManager::ShouldChangeVisibilityAfterDrag(
// The visibility of the shelf changes only if the shelf was dragged X%
// along the correct axis. If the shelf was already visible, then the
// direction of the drag does not matter.
const float kDragHideThreshold = 0.4f;
const gfx::Rect bounds = GetIdealBounds();
const float drag_ratio =
fabs(drag_amount_) /
(shelf_->IsHorizontalAlignment() ? bounds.height() : bounds.width());
return IsSwipingCorrectDirection() && drag_ratio > kDragHideThreshold;
return IsSwipingCorrectDirection() &&
drag_ratio > ShelfConfig::Get()->drag_hide_ratio_threshold();
}
if (event_in_screen.type() == ui::ET_SCROLL_FLING_START)

@@ -1,73 +0,0 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// 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_event_handler.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
namespace ash {
namespace {
// The height of the area in which a touch operation leads to exiting the
// full screen mode.
const int kLeaveFullScreenAreaHeightInPixel = 2;
} // namespace
TabletModeEventHandler::TabletModeEventHandler() {
Shell::Get()->AddPreTargetHandler(this);
}
TabletModeEventHandler::~TabletModeEventHandler() {
Shell::Get()->RemovePreTargetHandler(this);
}
void TabletModeEventHandler::OnTouchEvent(ui::TouchEvent* event) {
if (ToggleFullscreen(*event))
event->StopPropagation();
}
bool TabletModeEventHandler::ToggleFullscreen(const ui::TouchEvent& event) {
if (event.type() != ui::ET_TOUCH_PRESSED)
return false;
const SessionControllerImpl* controller = Shell::Get()->session_controller();
if (controller->IsScreenLocked() ||
controller->GetSessionState() != session_manager::SessionState::ACTIVE) {
return false;
}
// Find the active window (from the primary screen) to un-fullscreen.
aura::Window* window = window_util::GetActiveWindow();
if (!window)
return false;
WindowState* window_state = WindowState::Get(window);
if (!window_state->IsFullscreen() || window_state->IsInImmersiveFullscreen())
return false;
// Test that the touch happened in the top or bottom lines.
int y = event.y();
if (y >= kLeaveFullScreenAreaHeightInPixel &&
y < (window->bounds().height() - kLeaveFullScreenAreaHeightInPixel)) {
return false;
}
// Do not exit fullscreen in kiosk app mode.
if (Shell::Get()->session_controller()->IsRunningInAppMode())
return false;
WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
WindowState::Get(window)->OnWMEvent(&toggle_fullscreen);
return true;
}
} // namespace ash

@@ -1,37 +0,0 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_TABLET_MODE_TABLET_MODE_EVENT_HANDLER_H_
#define ASH_WM_TABLET_MODE_TABLET_MODE_EVENT_HANDLER_H_
#include "base/macros.h"
#include "ui/events/event_handler.h"
namespace ui {
class TouchEvent;
}
namespace ash {
// TabletModeEventHandler handles toggling fullscreen when appropriate.
// TabletModeEventHandler installs event handlers in an environment specific
// way, e.g. EventHandler for aura.
class TabletModeEventHandler : public ui::EventHandler {
public:
TabletModeEventHandler();
~TabletModeEventHandler() override;
private:
// ui::EventHandler:
void OnTouchEvent(ui::TouchEvent* event) override;
// Returns true if a toggle happened.
bool ToggleFullscreen(const ui::TouchEvent& event);
DISALLOW_COPY_AND_ASSIGN(TabletModeEventHandler);
};
} // namespace ash
#endif // ASH_WM_TABLET_MODE_TABLET_MODE_EVENT_HANDLER_H_

@@ -0,0 +1,139 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// 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/public/cpp/shelf_config.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
namespace ash {
namespace {
// The height of the area in which a touch operation leads to exiting the
// full screen mode.
constexpr int kLeaveFullScreenAreaHeightInPixel = 2;
} // namespace
TabletModeToggleFullscreenEventHandler::
TabletModeToggleFullscreenEventHandler() {
Shell::Get()->AddPreTargetHandler(this);
}
TabletModeToggleFullscreenEventHandler::
~TabletModeToggleFullscreenEventHandler() {
ResetDragData();
Shell::Get()->RemovePreTargetHandler(this);
}
void TabletModeToggleFullscreenEventHandler::OnTouchEvent(
ui::TouchEvent* event) {
if (ProcessEvent(*event)) {
event->SetHandled();
event->StopPropagation();
}
}
void TabletModeToggleFullscreenEventHandler::OnWindowDestroying(
aura::Window* window) {
DCHECK(drag_data_);
DCHECK_EQ(drag_data_->window, window);
ResetDragData();
}
bool TabletModeToggleFullscreenEventHandler::ProcessEvent(
const ui::TouchEvent& event) {
switch (event.type()) {
case ui::ET_TOUCH_PRESSED: {
DCHECK(!drag_data_);
aura::Window* active_window = window_util::GetActiveWindow();
if (!active_window || !CanToggleFullscreen(active_window))
return false;
const int y = event.y();
// For touch press events only process the ones on the top or bottom
// lines.
if (y >= kLeaveFullScreenAreaHeightInPixel &&
y < (active_window->bounds().height() -
kLeaveFullScreenAreaHeightInPixel)) {
return false;
}
drag_data_ = DragData{y, active_window};
active_window->AddObserver(this);
return true;
}
case ui::ET_TOUCH_RELEASED: {
if (!drag_data_)
return false;
// Toggle fullscreen if dragged enough and the window can still be
// fullscreened.
const int drag_threshold =
ShelfConfig::Get()->shelf_size() *
ShelfConfig::Get()->drag_hide_ratio_threshold();
if (abs(event.y() - drag_data_->start_y_location) > drag_threshold &&
CanToggleFullscreen(drag_data_->window)) {
WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
WindowState::Get(drag_data_->window)->OnWMEvent(&toggle_fullscreen);
}
ResetDragData();
return true;
}
case ui::ET_TOUCH_MOVED:
return drag_data_.has_value();
case ui::ET_TOUCH_CANCELLED: {
const bool drag_in_progress = drag_data_.has_value();
ResetDragData();
return drag_in_progress;
}
default:
break;
}
NOTREACHED();
return false;
}
bool TabletModeToggleFullscreenEventHandler::CanToggleFullscreen(
const aura::Window* window) {
DCHECK(window);
const SessionControllerImpl* controller = Shell::Get()->session_controller();
if (controller->IsScreenLocked() ||
controller->GetSessionState() != session_manager::SessionState::ACTIVE) {
return false;
}
// Find the active window (from the primary screen) to un-fullscreen.
aura::Window* active_window = window_util::GetActiveWindow();
if (window != active_window)
return false;
const WindowState* window_state = WindowState::Get(window);
if (!window_state->IsFullscreen() || window_state->IsInImmersiveFullscreen())
return false;
// Do not exit fullscreen in kiosk app mode.
if (Shell::Get()->session_controller()->IsRunningInAppMode())
return false;
return true;
}
void TabletModeToggleFullscreenEventHandler::ResetDragData() {
if (drag_data_)
drag_data_->window->RemoveObserver(this);
drag_data_.reset();
}
} // namespace ash

@@ -0,0 +1,57 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_TABLET_MODE_TABLET_MODE_TOGGLE_FULLSCREEN_EVENT_HANDLER_H_
#define ASH_WM_TABLET_MODE_TABLET_MODE_TOGGLE_FULLSCREEN_EVENT_HANDLER_H_
#include "ui/aura/window_observer.h"
#include "ui/events/event_handler.h"
namespace ui {
class TouchEvent;
}
namespace ash {
// TabletModeToggleFullscreenEventHandler handles toggling fullscreen when
// appropriate. TabletModeToggleFullscreenEventHandler installs event handlers
// in an environment specific way, e.g. EventHandler for aura.
class TabletModeToggleFullscreenEventHandler : public ui::EventHandler,
public aura::WindowObserver {
public:
TabletModeToggleFullscreenEventHandler();
TabletModeToggleFullscreenEventHandler(
const TabletModeToggleFullscreenEventHandler&) = delete;
TabletModeToggleFullscreenEventHandler& operator=(
const TabletModeToggleFullscreenEventHandler&) = delete;
~TabletModeToggleFullscreenEventHandler() override;
private:
struct DragData {
int start_y_location;
aura::Window* window;
};
// ui::EventHandler:
void OnTouchEvent(ui::TouchEvent* event) override;
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
bool ProcessEvent(const ui::TouchEvent& event);
// Returns true if |window| can be fullscreen toggled.
bool CanToggleFullscreen(const aura::Window* window);
// Resets |drag_data_| and remove the WindowObserver.
void ResetDragData();
// Valid if a processable drag is in progress. Contains the event initial
// location and the window that was active when the drag started.
base::Optional<DragData> drag_data_;
};
} // namespace ash
#endif // ASH_WM_TABLET_MODE_TABLET_MODE_TOGGLE_FULLSCREEN_EVENT_HANDLER_H_

@@ -0,0 +1,171 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// 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/public/cpp/window_properties.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.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(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(400, start_y), gfx::Point(400, end_y),
base::TimeDelta::FromMilliseconds(100), 3);
}
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()));
}
} // namespace ash

@@ -23,7 +23,7 @@
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/tablet_mode/scoped_skip_user_session_blocked_check.h"
#include "ash/wm/tablet_mode/tablet_mode_event_handler.h"
#include "ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.h"
#include "ash/wm/tablet_mode/tablet_mode_window_state.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
@@ -158,7 +158,7 @@ void TabletModeWindowManager::Init() {
Shell::Get()->overview_controller()->AddObserver(this);
accounts_since_entering_tablet_.insert(
Shell::Get()->session_controller()->GetActiveAccountId());
event_handler_ = std::make_unique<TabletModeEventHandler>();
event_handler_ = std::make_unique<TabletModeToggleFullscreenEventHandler>();
}
void TabletModeWindowManager::Shutdown() {

@@ -29,7 +29,7 @@ class Window;
namespace ash {
class TabletModeController;
class TabletModeEventHandler;
class TabletModeToggleFullscreenEventHandler;
class TabletModeWindowState;
// A window manager which - when created - will force all windows into maximized
@@ -184,7 +184,7 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
// All accounts that have been active at least once since tablet mode started.
base::flat_set<AccountId> accounts_since_entering_tablet_;
std::unique_ptr<TabletModeEventHandler> event_handler_;
std::unique_ptr<TabletModeToggleFullscreenEventHandler> event_handler_;
// True when tablet mode is about to end.
bool is_exiting_ = false;

@@ -1318,215 +1318,6 @@ TEST_P(TabletModeWindowManagerTest, TryToDesktopSizeDragUnmaximizable) {
EXPECT_EQ(first_dragged_origin.y() + 5, window->bounds().y());
}
// Test that an edge swipe from the top will end full screen mode.
TEST_P(TabletModeWindowManagerTest, ExitFullScreenWithEdgeSwipeFromTop) {
gfx::Rect rect(10, 10, 200, 50);
std::unique_ptr<aura::Window> background_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
std::unique_ptr<aura::Window> foreground_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
WindowState* background_window_state =
WindowState::Get(background_window.get());
WindowState* foreground_window_state =
WindowState::Get(foreground_window.get());
wm::ActivateWindow(foreground_window.get());
CreateTabletModeWindowManager();
// Fullscreen both windows.
WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN);
background_window_state->OnWMEvent(&event);
foreground_window_state->OnWMEvent(&event);
EXPECT_TRUE(background_window_state->IsFullscreen());
EXPECT_TRUE(foreground_window_state->IsFullscreen());
EXPECT_EQ(foreground_window.get(), window_util::GetActiveWindow());
// Do an edge swipe top into screen.
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
generator.GestureScrollSequence(gfx::Point(50, 0), gfx::Point(50, 100),
base::TimeDelta::FromMilliseconds(20), 10);
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
// Do a second edge swipe top into screen.
generator.GestureScrollSequence(gfx::Point(50, 0), gfx::Point(50, 100),
base::TimeDelta::FromMilliseconds(20), 10);
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
DestroyTabletModeWindowManager();
}
// Test that an edge swipe from the bottom will end full screen mode.
TEST_P(TabletModeWindowManagerTest, ExitFullScreenWithEdgeSwipeFromBottom) {
gfx::Rect rect(10, 10, 200, 50);
std::unique_ptr<aura::Window> background_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
std::unique_ptr<aura::Window> foreground_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
WindowState* background_window_state =
WindowState::Get(background_window.get());
WindowState* foreground_window_state =
WindowState::Get(foreground_window.get());
wm::ActivateWindow(foreground_window.get());
CreateTabletModeWindowManager();
// Fullscreen both windows.
WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN);
background_window_state->OnWMEvent(&event);
foreground_window_state->OnWMEvent(&event);
EXPECT_TRUE(background_window_state->IsFullscreen());
EXPECT_TRUE(foreground_window_state->IsFullscreen());
EXPECT_EQ(foreground_window.get(), window_util::GetActiveWindow());
// Do an edge swipe bottom into screen.
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
int y = Shell::GetPrimaryRootWindow()->bounds().bottom();
generator.GestureScrollSequence(gfx::Point(50, y), gfx::Point(50, y - 100),
base::TimeDelta::FromMilliseconds(20), 10);
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
DestroyTabletModeWindowManager();
}
// Test that an edge touch press at the top will end full screen mode.
TEST_P(TabletModeWindowManagerTest, ExitFullScreenWithEdgeTouchAtTop) {
gfx::Rect rect(10, 10, 200, 50);
std::unique_ptr<aura::Window> background_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
std::unique_ptr<aura::Window> foreground_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
WindowState* background_window_state =
WindowState::Get(background_window.get());
WindowState* foreground_window_state =
WindowState::Get(foreground_window.get());
wm::ActivateWindow(foreground_window.get());
CreateTabletModeWindowManager();
// Fullscreen both windows.
WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN);
background_window_state->OnWMEvent(&event);
foreground_window_state->OnWMEvent(&event);
EXPECT_TRUE(background_window_state->IsFullscreen());
EXPECT_TRUE(foreground_window_state->IsFullscreen());
EXPECT_EQ(foreground_window.get(), window_util::GetActiveWindow());
// Touch tap on the top edge.
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
generator.GestureTapAt(gfx::Point(100, 0));
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
// Try the same again and see that nothing changes.
generator.GestureTapAt(gfx::Point(100, 0));
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
DestroyTabletModeWindowManager();
}
// Test that an edge touch press at the bottom will end full screen mode.
TEST_P(TabletModeWindowManagerTest, ExitFullScreenWithEdgeTouchAtBottom) {
gfx::Rect rect(10, 10, 200, 50);
std::unique_ptr<aura::Window> background_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
std::unique_ptr<aura::Window> foreground_window(
CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
WindowState* background_window_state =
WindowState::Get(background_window.get());
WindowState* foreground_window_state =
WindowState::Get(foreground_window.get());
wm::ActivateWindow(foreground_window.get());
CreateTabletModeWindowManager();
// Fullscreen both windows.
WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN);
background_window_state->OnWMEvent(&event);
foreground_window_state->OnWMEvent(&event);
EXPECT_TRUE(background_window_state->IsFullscreen());
EXPECT_TRUE(foreground_window_state->IsFullscreen());
EXPECT_EQ(foreground_window.get(), window_util::GetActiveWindow());
// Touch tap on the bottom edge.
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
generator.GestureTapAt(
gfx::Point(100, Shell::GetPrimaryRootWindow()->bounds().bottom() - 1));
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
// Try the same again and see that nothing changes.
generator.GestureTapAt(
gfx::Point(100, Shell::GetPrimaryRootWindow()->bounds().bottom() - 1));
EXPECT_FALSE(foreground_window_state->IsFullscreen());
EXPECT_TRUE(background_window_state->IsFullscreen());
DestroyTabletModeWindowManager();
}
// Test that an edge swipe from the top on an immersive mode window will not end
// full screen mode.
TEST_P(TabletModeWindowManagerTest, NoExitImmersiveModeWithEdgeSwipeFromTop) {
std::unique_ptr<aura::Window> window(CreateWindow(
aura::client::WINDOW_TYPE_NORMAL, gfx::Rect(10, 10, 200, 50)));
WindowState* window_state = WindowState::Get(window.get());
wm::ActivateWindow(window.get());
CreateTabletModeWindowManager();
// Fullscreen the window.
WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN);
window_state->OnWMEvent(&event);
EXPECT_TRUE(window_state->IsFullscreen());
EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
window->SetProperty(kImmersiveIsActive, true);
// Do an edge swipe top into screen.
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
generator.GestureScrollSequence(gfx::Point(50, 0), gfx::Point(50, 100),
base::TimeDelta::FromMilliseconds(20), 10);
// It should have not exited full screen or immersive mode.
EXPECT_TRUE(window_state->IsFullscreen());
EXPECT_TRUE(window_state->IsInImmersiveFullscreen());
DestroyTabletModeWindowManager();
}
// Test that an edge swipe from the bottom will not end immersive mode.
TEST_P(TabletModeWindowManagerTest,
NoExitImmersiveModeWithEdgeSwipeFromBottom) {
std::unique_ptr<aura::Window> window(CreateWindow(
aura::client::WINDOW_TYPE_NORMAL, gfx::Rect(10, 10, 200, 50)));
WindowState* window_state = WindowState::Get(window.get());
wm::ActivateWindow(window.get());
CreateTabletModeWindowManager();
// Fullscreen the window.
WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN);
window_state->OnWMEvent(&event);
EXPECT_TRUE(window_state->IsFullscreen());
EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
window->SetProperty(kImmersiveIsActive, true);
EXPECT_TRUE(window_state->IsInImmersiveFullscreen());
// Do an edge swipe bottom into screen.
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
int y = Shell::GetPrimaryRootWindow()->bounds().bottom();
generator.GestureScrollSequence(gfx::Point(50, y), gfx::Point(50, y - 100),
base::TimeDelta::FromMilliseconds(20), 10);
// The window should still be full screen and immersive.
EXPECT_TRUE(window_state->IsFullscreen());
EXPECT_TRUE(window_state->IsInImmersiveFullscreen());
DestroyTabletModeWindowManager();
}
// Tests that windows with the always-on-top property are not managed by
// the TabletModeWindowManager while tablet mode is engaged (i.e.,
// they remain free-floating).