Commit 2aa4de6f authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

Virtual Desks: Switch drag-to-close to normal-drag when dragged into desks bar

In order to provide a better user experience, we allow cancelling drag-to-close
and switch it to normal drag once the drag location enters the desks bar bounds.
This way users won't have to drop the item first and start dragging again.

Demo: https://bugs.chromium.org/p/chromium/issues/detail?id=972371#c3

BUG=866622, 972371
TEST=Manually, Added a new test.

Change-Id: I9c5683ed04eff230633d09f81837c1db45883f81
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1703544Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#678024}
parent 89572d5d
......@@ -1054,8 +1054,8 @@ TEST_P(DesksTest, DragWindowToDesk) {
EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
EXPECT_TRUE(DoesActiveDeskContainWindow(win1.get()));
// Now drag it to desk_2's mini_view. The overview grid should now show the
// "no-windows" widget, and the window should move to desk_2.
// Now drag it to desk_2's mini_view. The overview grid should now have only
// `win2`, and `win1` should move to desk_2.
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
EXPECT_EQ(desk_2, desk_2_mini_view->desk());
DragItemToPoint(overview_item,
......
......@@ -1190,14 +1190,17 @@ gfx::Rect OverviewGrid::GetGridEffectiveBounds() const {
return effective_bounds;
}
bool OverviewGrid::UpdateDesksBarDragDetails(const gfx::Point& screen_location,
bool OverviewGrid::IntersectsWithDesksBar(const gfx::Point& screen_location,
bool update_desks_bar_drag_details,
bool for_drop) {
DCHECK(desks_util::ShouldDesksBarBeCreated());
const bool dragged_item_over_bar =
desks_widget_->GetWindowBoundsInScreen().Contains(screen_location);
if (update_desks_bar_drag_details) {
desks_bar_view_->SetDragDetails(screen_location,
!for_drop && dragged_item_over_bar);
}
return dragged_item_over_bar;
}
......@@ -1207,8 +1210,11 @@ bool OverviewGrid::MaybeDropItemOnDeskMiniView(
DCHECK(desks_util::ShouldDesksBarBeCreated());
// End the drag for the DesksBarView.
if (!UpdateDesksBarDragDetails(screen_location, /*for_drop=*/true))
if (!IntersectsWithDesksBar(screen_location,
/*update_desks_bar_drag_details=*/true,
/*for_drop=*/true)) {
return false;
}
auto* desks_controller = DesksController::Get();
for (auto& mini_view : desks_bar_view_->mini_views()) {
......
......@@ -248,12 +248,14 @@ class ASH_EXPORT OverviewGrid : public aura::WindowObserver,
// positioned, taking into account the availability of the Desks bar).
gfx::Rect GetGridEffectiveBounds() const;
// Called when a window is being dragged in Overview Mode to update the drag
// details (screen_location, and whether that location intersects with the
// desks bar widget. |for_drop| should be set to true if this is called when
// the item is being dropped when the drag is complete
// Called when a window is being dragged in Overview Mode. If
// |update_desks_bar_drag_details| is true, it will update the drag details
// (screen_location, and whether that location intersects with the
// desks bar widget). |for_drop| should be set to true if this is called when
// the item is being dropped when the drag is complete.
// Returns true if |screen_location| does intersect with the DesksBarView.
bool UpdateDesksBarDragDetails(const gfx::Point& screen_location,
bool IntersectsWithDesksBar(const gfx::Point& screen_location,
bool update_desks_bar_drag_details,
bool for_drop);
// Updates the drag details for DesksBarView to end the drag and move the
......
......@@ -298,6 +298,18 @@ void OverviewWindowDragController::ContinueDragToClose(
const gfx::PointF centerpoint =
location_in_screen - (initial_event_location_ - initial_centerpoint_);
// If the drag location intersects with the desk bar, then we should cancel
// the drag-to-close mode and start the normal drag mode.
if (virtual_desks_bar_enabled_ &&
item_->overview_grid()->IntersectsWithDesksBar(
gfx::ToRoundedPoint(location_in_screen),
/*update_desks_bar_drag_details=*/false, /*for_drop=*/false)) {
item_->SetOpacity(original_opacity_);
StartNormalDragMode(location_in_screen);
ContinueNormalDrag(location_in_screen);
return;
}
// Update |item_|'s opacity based on its distance. |item_|'s x coordinate
// should not change while in drag to close state.
float val = std::abs(location_in_screen.y() - initial_event_location_.y()) /
......@@ -348,8 +360,9 @@ void OverviewWindowDragController::ContinueNormalDrag(
bool allow_original_window_opacity_change = true;
if (virtual_desks_bar_enabled_) {
if (item_->overview_grid()->UpdateDesksBarDragDetails(
gfx::ToRoundedPoint(location_in_screen), /*for_drop=*/false)) {
if (item_->overview_grid()->IntersectsWithDesksBar(
gfx::ToRoundedPoint(location_in_screen),
/*update_desks_bar_drag_details=*/true, /*for_drop=*/false)) {
// The drag location intersects the bounds of the DesksBarView, in this
// case we scale down the item, and center it around the drag location.
bounds.set_size(on_desks_bar_item_size_);
......
......@@ -7,6 +7,9 @@
#include "ash/public/cpp/ash_features.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desk_mini_view.h"
#include "ash/wm/desks/desks_bar_view.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
......@@ -198,4 +201,80 @@ TEST_F(OverviewWindowDragControllerTest, NoDragToCloseUsingMouse) {
EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
}
class OverviewWindowDragControllerWithDesksTest : public AshTestBase {
public:
OverviewWindowDragControllerWithDesksTest() = default;
~OverviewWindowDragControllerWithDesksTest() override = default;
// AshTestBase:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(features::kVirtualDesks);
AshTestBase::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(OverviewWindowDragControllerWithDesksTest);
};
TEST_F(OverviewWindowDragControllerWithDesksTest,
SwitchDragToCloseToNormalDragWhendraggedToDesk) {
UpdateDisplay("600x800");
auto* controller = DesksController::Get();
controller->NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto window = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), wm::GetActiveWindow());
auto* overview_controller = Shell::Get()->overview_controller();
overview_controller->StartOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_session = overview_controller->overview_session();
const auto* overview_grid =
overview_session->GetGridWithRootWindow(Shell::GetPrimaryRootWindow());
ASSERT_TRUE(overview_grid);
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
ASSERT_TRUE(overview_item);
const gfx::RectF target_bounds_before_drag = overview_item->target_bounds();
// Drag with touch gesture only vertically without intersecting with the desk
// bar, which should trigger the drag-to-close mode.
const int item_center_to_desks_bar_bottom =
gfx::ToRoundedPoint(target_bounds_before_drag.CenterPoint()).y() -
desks_bar_view->GetBoundsInScreen().bottom();
EXPECT_GT(item_center_to_desks_bar_bottom, 0);
const int space_to_leave = 20;
auto* event_generator = GetEventGenerator();
StartDraggingItemBy(overview_item, 0,
-(item_center_to_desks_bar_bottom - space_to_leave),
/*by_touch_gestures=*/true, event_generator);
OverviewWindowDragController* drag_controller =
overview_session->window_drag_controller();
EXPECT_EQ(OverviewWindowDragController::DragBehavior::kDragToClose,
drag_controller->current_drag_behavior());
// Continue dragging vertically up such that the drag location intersects with
// the desks bar. Expect that normal drag is now triggered.
event_generator->MoveTouchBy(0, -(space_to_leave + 10));
EXPECT_EQ(OverviewWindowDragController::DragBehavior::kNormalDrag,
drag_controller->current_drag_behavior());
// Now it's possible to drop it on desk_2's mini_view.
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
ASSERT_TRUE(desk_2_mini_view);
event_generator->MoveTouch(
desk_2_mini_view->GetBoundsInScreen().CenterPoint());
event_generator->ReleaseTouch();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(overview_grid->empty());
const Desk* desk_2 = controller->desks()[1].get();
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
EXPECT_TRUE(overview_session->no_windows_widget_for_testing());
}
} // namespace ash
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