Commit 117881cc authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

Fling from overview to home screen

Adds back fling from overview to home screen when
kDragFromShelfToHomeOrOverview is enabled.
With the feature disabled, drag/fling from bottom in overview transitions
to home, and is handled by HomeLauncherGestureHandler. When the feature
is enabled, the gesture is not propagated to HomeLauncherGestureHandler
(as it might have to handle hotseat drag in split view).

This adds handling for the fling in overview to shelf_layout_manager, to
re-enable the gesture - the handling is moved from
HomeLauncherGestureHandler to ShelfLayoutManager to better handle the
case where the hotseat starts off in the hidden state (and fling in
split view can either bring up the hotseat, or go to home screen,
depending on the gesture length) -  handling the gesture in
HomeLauncherGestureHandler means that the drag event would not be
handled as shelf drag event (which brings up the hotseat).

The fling is expected to transition to home if:
*   in overview mode
*   in split view mode with overview, and fling is on the overview
    side (otherwise, the gesture should be handled by
    window_drag_controller_)

BUG=1023910

Change-Id: I2385d195aa06f04d264da926091e6fc4b5f8fe26
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935107
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718971}
parent 375e9c25
...@@ -210,6 +210,7 @@ aura::Window* GetWindowForDragToHomeOrOverview( ...@@ -210,6 +210,7 @@ aura::Window* GetWindowForDragToHomeOrOverview(
// Returns the null value if no gesture should be recorded. // Returns the null value if no gesture should be recorded.
base::Optional<InAppShelfGestures> CalculateHotseatGestureToRecord( base::Optional<InAppShelfGestures> CalculateHotseatGestureToRecord(
base::Optional<ShelfWindowDragResult> window_drag_result, base::Optional<ShelfWindowDragResult> window_drag_result,
bool transitioned_from_overview_to_home,
HotseatState old_state, HotseatState old_state,
HotseatState current_state) { HotseatState current_state) {
if (window_drag_result.has_value() && if (window_drag_result.has_value() &&
...@@ -223,6 +224,9 @@ base::Optional<InAppShelfGestures> CalculateHotseatGestureToRecord( ...@@ -223,6 +224,9 @@ base::Optional<InAppShelfGestures> CalculateHotseatGestureToRecord(
return InAppShelfGestures::kFlingUpToShowHomeScreen; return InAppShelfGestures::kFlingUpToShowHomeScreen;
} }
if (transitioned_from_overview_to_home)
return InAppShelfGestures::kFlingUpToShowHomeScreen;
if (old_state == current_state) if (old_state == current_state)
return base::nullopt; return base::nullopt;
...@@ -2366,6 +2370,15 @@ void ShelfLayoutManager::CompleteDrag(const ui::LocatedEvent& event_in_screen) { ...@@ -2366,6 +2370,15 @@ void ShelfLayoutManager::CompleteDrag(const ui::LocatedEvent& event_in_screen) {
MaybeEndWindowDrag(event_in_screen); MaybeEndWindowDrag(event_in_screen);
HotseatState old_hotseat_state = hotseat_state(); HotseatState old_hotseat_state = hotseat_state();
const bool transitioned_from_overview_to_home =
MaybeEndDragFromOverviewToHome(event_in_screen);
allow_fling_from_overview_to_home_ = false;
// Fling from overview to home should be allowed only if window_drag_handler_
// is not handling a window.
DCHECK(!transitioned_from_overview_to_home ||
!window_drag_result.has_value());
if (ShouldChangeVisibilityAfterDrag(event_in_screen)) if (ShouldChangeVisibilityAfterDrag(event_in_screen))
CompleteDragWithChangedVisibility(); CompleteDragWithChangedVisibility();
else else
...@@ -2374,8 +2387,9 @@ void ShelfLayoutManager::CompleteDrag(const ui::LocatedEvent& event_in_screen) { ...@@ -2374,8 +2387,9 @@ void ShelfLayoutManager::CompleteDrag(const ui::LocatedEvent& event_in_screen) {
// Hotseat gestures are meaningful only in tablet mode with hotseat enabled. // Hotseat gestures are meaningful only in tablet mode with hotseat enabled.
if (chromeos::switches::ShouldShowShelfHotseat() && IsTabletModeEnabled()) { if (chromeos::switches::ShouldShowShelfHotseat() && IsTabletModeEnabled()) {
base::Optional<InAppShelfGestures> gesture_to_record = base::Optional<InAppShelfGestures> gesture_to_record =
CalculateHotseatGestureToRecord(window_drag_result, old_hotseat_state, CalculateHotseatGestureToRecord(window_drag_result,
hotseat_state()); transitioned_from_overview_to_home,
old_hotseat_state, hotseat_state());
if (gesture_to_record.has_value()) { if (gesture_to_record.has_value()) {
UMA_HISTOGRAM_ENUMERATION(kHotseatGestureHistogramName, UMA_HISTOGRAM_ENUMERATION(kHotseatGestureHistogramName,
gesture_to_record.value()); gesture_to_record.value());
...@@ -2619,6 +2633,7 @@ bool ShelfLayoutManager::MaybeStartDragWindowFromShelf( ...@@ -2619,6 +2633,7 @@ bool ShelfLayoutManager::MaybeStartDragWindowFromShelf(
aura::Window* window = aura::Window* window =
GetWindowForDragToHomeOrOverview(event_in_screen.location()); GetWindowForDragToHomeOrOverview(event_in_screen.location());
allow_fling_from_overview_to_home_ = !window;
if (!window) if (!window)
return false; return false;
...@@ -2657,6 +2672,43 @@ base::Optional<ShelfWindowDragResult> ShelfLayoutManager::MaybeEndWindowDrag( ...@@ -2657,6 +2672,43 @@ base::Optional<ShelfWindowDragResult> ShelfLayoutManager::MaybeEndWindowDrag(
velocity_y); velocity_y);
} }
bool ShelfLayoutManager::MaybeEndDragFromOverviewToHome(
const ui::LocatedEvent& event_in_screen) {
if (!IsHotseatEnabled())
return false;
if (!allow_fling_from_overview_to_home_ ||
!Shell::Get()->overview_controller()->InOverviewSession()) {
return false;
}
if (event_in_screen.type() != ui::ET_SCROLL_FLING_START)
return false;
const float velocity_y =
event_in_screen.AsGestureEvent()->details().velocity_y();
if (velocity_y >
-DragWindowFromShelfController::kVelocityToHomeScreenThreshold) {
return false;
}
// If the drag started from hidden hotseat, check that the swipe length is
// sufficiently longer than the amount needed to fling the hotseat up, to
// reduce false positives when the user is pulling up the hotseat.
if (hotseat_state() == HotseatState::kHidden) {
const float kHotseatSizeMultiplier = 2;
ShelfConfig* shelf_config = ShelfConfig::Get();
const int drag_amount_threshold =
-(shelf_config->shelf_size() + shelf_config->hotseat_bottom_padding() +
kHotseatSizeMultiplier * shelf_config->hotseat_size());
if (drag_amount_ > drag_amount_threshold)
return false;
}
Shell::Get()->home_screen_controller()->GoHome(display_.id());
return true;
}
void ShelfLayoutManager::MaybeCancelWindowDrag() { void ShelfLayoutManager::MaybeCancelWindowDrag() {
if (!IsWindowDragInProgress()) if (!IsWindowDragInProgress())
return; return;
......
...@@ -531,6 +531,11 @@ class ASH_EXPORT ShelfLayoutManager : public AppListControllerObserver, ...@@ -531,6 +531,11 @@ class ASH_EXPORT ShelfLayoutManager : public AppListControllerObserver,
float scroll_y); float scroll_y);
base::Optional<DragWindowFromShelfController::ShelfWindowDragResult> base::Optional<DragWindowFromShelfController::ShelfWindowDragResult>
MaybeEndWindowDrag(const ui::LocatedEvent& event_in_screen); MaybeEndWindowDrag(const ui::LocatedEvent& event_in_screen);
// If overview session is active, goes to home screen if the gesture should
// initiate transition to home. It handles the gesture only if the
// |window_drag_controller_| is not handling a window drag (for example, in
// split view mode).
bool MaybeEndDragFromOverviewToHome(const ui::LocatedEvent& event_in_screen);
void MaybeCancelWindowDrag(); void MaybeCancelWindowDrag();
bool IsWindowDragInProgress() const; bool IsWindowDragInProgress() const;
...@@ -671,6 +676,14 @@ class ASH_EXPORT ShelfLayoutManager : public AppListControllerObserver, ...@@ -671,6 +676,14 @@ class ASH_EXPORT ShelfLayoutManager : public AppListControllerObserver,
// up from shelf to homescreen, overview or splitview. // up from shelf to homescreen, overview or splitview.
std::unique_ptr<DragWindowFromShelfController> window_drag_controller_; std::unique_ptr<DragWindowFromShelfController> window_drag_controller_;
// Whether upward fling from shelf should be handled as potential gesture from
// overview to home. This is set when the swipe would otherwise be handled by
// |window_drag_controller_|, but the swipe cannot be associated with a window
// to drag (for example, because the swipe started in split view mode on a
// side which is showing overview). Note that the gesture will be handled only
// if the overview session is active.
bool allow_fling_from_overview_to_home_ = false;
// Tracks whether the shelf is currently dimmed for inactivity. // Tracks whether the shelf is currently dimmed for inactivity.
bool dimmed_for_inactivity_ = false; bool dimmed_for_inactivity_ = false;
......
...@@ -4820,6 +4820,150 @@ TEST_F(ShelfLayoutManagerWindowDraggingTest, NoOpInOverview) { ...@@ -4820,6 +4820,150 @@ TEST_F(ShelfLayoutManagerWindowDraggingTest, NoOpInOverview) {
EndScroll(/*is_fling=*/false, 0.f); EndScroll(/*is_fling=*/false, 0.f);
} }
// Test that upward fling in overview transitions from overview to home.
TEST_F(ShelfLayoutManagerWindowDraggingTest, FlingInOverview) {
const gfx::Rect shelf_widget_bounds =
GetShelfWidget()->GetWindowBoundsInScreen();
const int shelf_size = ShelfConfig::Get()->shelf_size();
const int hotseat_size = ShelfConfig::Get()->hotseat_size();
const int hotseat_padding_size = ShelfConfig::Get()->hotseat_bottom_padding();
std::unique_ptr<aura::Window> window1 =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
wm::ActivateWindow(window1.get());
OverviewController* overview_controller = Shell::Get()->overview_controller();
overview_controller->StartOverview();
base::HistogramTester histogram_tester;
HotseatStateWatcher watcher(GetShelfLayoutManager());
// Fling up from the center of the shelf's bottom.
StartScroll(shelf_widget_bounds.bottom_center());
UpdateScroll(-shelf_size - hotseat_size - hotseat_padding_size);
EndScroll(
true /* is_fling */,
-(DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 10));
EXPECT_FALSE(overview_controller->InOverviewSession());
watcher.WaitUntilStateChanged();
watcher.CheckEqual({HotseatState::kShown});
histogram_tester.ExpectBucketCount(
kHotseatGestureHistogramName,
InAppShelfGestures::kFlingUpToShowHomeScreen, 1);
histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName,
InAppShelfGestures::kSwipeUpToShow, 0);
}
// Test that upward fling in split mode on overview side shows hotseat and
// remains in split view is the swipe is short.
TEST_F(ShelfLayoutManagerWindowDraggingTest,
FlingToShowHotseatInSplitModeWithOverview) {
const gfx::Rect shelf_widget_bounds =
GetShelfWidget()->GetWindowBoundsInScreen();
const int shelf_size = ShelfConfig::Get()->shelf_size();
const int hotseat_size = ShelfConfig::Get()->hotseat_size();
const int hotseat_padding_size = ShelfConfig::Get()->hotseat_bottom_padding();
std::unique_ptr<aura::Window> window1 =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
std::unique_ptr<aura::Window> window2 =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
SplitViewController* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
OverviewController* overview_controller = Shell::Get()->overview_controller();
overview_controller->StartOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
base::HistogramTester histogram_tester;
HotseatStateWatcher watcher(GetShelfLayoutManager());
// Short fling (little longer than the drag required to show the extended
// hotseat).
StartScroll(shelf_widget_bounds.bottom_right());
UpdateScroll(-shelf_size - 1.5f * hotseat_size - hotseat_padding_size);
EndScroll(
true /* is_fling */,
-(DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 10));
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(split_view_controller->InSplitViewMode());
watcher.CheckEqual({HotseatState::kExtended});
histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName,
InAppShelfGestures::kSwipeUpToShow, 1);
// The same fling gesture should transition to home if the hotseat is in
// extended state.
StartScroll(shelf_widget_bounds.bottom_right());
UpdateScroll(-shelf_size - 1.5f * hotseat_size - hotseat_padding_size);
EndScroll(
true /* is_fling */,
-(DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 10));
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_FALSE(split_view_controller->InSplitViewMode());
watcher.WaitUntilStateChanged();
watcher.CheckEqual({HotseatState::kExtended, HotseatState::kShown});
histogram_tester.ExpectBucketCount(
kHotseatGestureHistogramName,
InAppShelfGestures::kFlingUpToShowHomeScreen, 1);
histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName,
InAppShelfGestures::kSwipeUpToShow, 1);
}
// Test that upward fling in split mode on overview side transitions to home, if
// the swipe length is long enough.
TEST_F(ShelfLayoutManagerWindowDraggingTest, FlingHomeInSplitModeWithOverview) {
const gfx::Rect shelf_widget_bounds =
GetShelfWidget()->GetWindowBoundsInScreen();
const int shelf_size = ShelfConfig::Get()->shelf_size();
const int hotseat_size = ShelfConfig::Get()->hotseat_size();
const int hotseat_padding_size = ShelfConfig::Get()->hotseat_bottom_padding();
std::unique_ptr<aura::Window> window1 =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
std::unique_ptr<aura::Window> window2 =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
SplitViewController* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
OverviewController* overview_controller = Shell::Get()->overview_controller();
overview_controller->StartOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
base::HistogramTester histogram_tester;
HotseatStateWatcher watcher(GetShelfLayoutManager());
// Longer fling, one that significantly exceeds the distance required to show
// the hotseat (by 2 hotseat heights).
StartScroll(shelf_widget_bounds.bottom_right());
UpdateScroll(-shelf_size - 3 * hotseat_size - hotseat_padding_size);
EndScroll(
true /* is_fling */,
-(DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 10));
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_FALSE(split_view_controller->InSplitViewMode());
watcher.WaitUntilStateChanged();
EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
histogram_tester.ExpectBucketCount(
kHotseatGestureHistogramName,
InAppShelfGestures::kFlingUpToShowHomeScreen, 1);
histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName,
InAppShelfGestures::kSwipeUpToShow, 0);
}
// Test that if shelf if hidden or auto-hide hidden, drag window from shelf is a // Test that if shelf if hidden or auto-hide hidden, drag window from shelf is a
// no-op. // no-op.
// TODO(1024163): This test consistently crashes. // TODO(1024163): This test consistently crashes.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment