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) { ...@@ -1054,8 +1054,8 @@ TEST_P(DesksTest, DragWindowToDesk) {
EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds()); EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
EXPECT_TRUE(DoesActiveDeskContainWindow(win1.get())); EXPECT_TRUE(DoesActiveDeskContainWindow(win1.get()));
// Now drag it to desk_2's mini_view. The overview grid should now show the // Now drag it to desk_2's mini_view. The overview grid should now have only
// "no-windows" widget, and the window should move to desk_2. // `win2`, and `win1` should move to desk_2.
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get(); auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
EXPECT_EQ(desk_2, desk_2_mini_view->desk()); EXPECT_EQ(desk_2, desk_2_mini_view->desk());
DragItemToPoint(overview_item, DragItemToPoint(overview_item,
......
...@@ -1190,14 +1190,17 @@ gfx::Rect OverviewGrid::GetGridEffectiveBounds() const { ...@@ -1190,14 +1190,17 @@ gfx::Rect OverviewGrid::GetGridEffectiveBounds() const {
return effective_bounds; return effective_bounds;
} }
bool OverviewGrid::UpdateDesksBarDragDetails(const gfx::Point& screen_location, bool OverviewGrid::IntersectsWithDesksBar(const gfx::Point& screen_location,
bool for_drop) { bool update_desks_bar_drag_details,
bool for_drop) {
DCHECK(desks_util::ShouldDesksBarBeCreated()); DCHECK(desks_util::ShouldDesksBarBeCreated());
const bool dragged_item_over_bar = const bool dragged_item_over_bar =
desks_widget_->GetWindowBoundsInScreen().Contains(screen_location); desks_widget_->GetWindowBoundsInScreen().Contains(screen_location);
desks_bar_view_->SetDragDetails(screen_location, if (update_desks_bar_drag_details) {
!for_drop && dragged_item_over_bar); desks_bar_view_->SetDragDetails(screen_location,
!for_drop && dragged_item_over_bar);
}
return dragged_item_over_bar; return dragged_item_over_bar;
} }
...@@ -1207,8 +1210,11 @@ bool OverviewGrid::MaybeDropItemOnDeskMiniView( ...@@ -1207,8 +1210,11 @@ bool OverviewGrid::MaybeDropItemOnDeskMiniView(
DCHECK(desks_util::ShouldDesksBarBeCreated()); DCHECK(desks_util::ShouldDesksBarBeCreated());
// End the drag for the DesksBarView. // 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; return false;
}
auto* desks_controller = DesksController::Get(); auto* desks_controller = DesksController::Get();
for (auto& mini_view : desks_bar_view_->mini_views()) { for (auto& mini_view : desks_bar_view_->mini_views()) {
......
...@@ -248,13 +248,15 @@ class ASH_EXPORT OverviewGrid : public aura::WindowObserver, ...@@ -248,13 +248,15 @@ class ASH_EXPORT OverviewGrid : public aura::WindowObserver,
// positioned, taking into account the availability of the Desks bar). // positioned, taking into account the availability of the Desks bar).
gfx::Rect GetGridEffectiveBounds() const; gfx::Rect GetGridEffectiveBounds() const;
// Called when a window is being dragged in Overview Mode to update the drag // Called when a window is being dragged in Overview Mode. If
// details (screen_location, and whether that location intersects with the // |update_desks_bar_drag_details| is true, it will update the drag details
// desks bar widget. |for_drop| should be set to true if this is called when // (screen_location, and whether that location intersects with the
// the item is being dropped when the drag is complete // 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. // 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 for_drop); bool update_desks_bar_drag_details,
bool for_drop);
// Updates the drag details for DesksBarView to end the drag and move the // Updates the drag details for DesksBarView to end the drag and move the
// window of |drag_item| to another desk if it was dropped on a mini_view of // window of |drag_item| to another desk if it was dropped on a mini_view of
......
...@@ -298,6 +298,18 @@ void OverviewWindowDragController::ContinueDragToClose( ...@@ -298,6 +298,18 @@ void OverviewWindowDragController::ContinueDragToClose(
const gfx::PointF centerpoint = const gfx::PointF centerpoint =
location_in_screen - (initial_event_location_ - initial_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 // Update |item_|'s opacity based on its distance. |item_|'s x coordinate
// should not change while in drag to close state. // should not change while in drag to close state.
float val = std::abs(location_in_screen.y() - initial_event_location_.y()) / float val = std::abs(location_in_screen.y() - initial_event_location_.y()) /
...@@ -348,8 +360,9 @@ void OverviewWindowDragController::ContinueNormalDrag( ...@@ -348,8 +360,9 @@ void OverviewWindowDragController::ContinueNormalDrag(
bool allow_original_window_opacity_change = true; bool allow_original_window_opacity_change = true;
if (virtual_desks_bar_enabled_) { if (virtual_desks_bar_enabled_) {
if (item_->overview_grid()->UpdateDesksBarDragDetails( if (item_->overview_grid()->IntersectsWithDesksBar(
gfx::ToRoundedPoint(location_in_screen), /*for_drop=*/false)) { 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 // The drag location intersects the bounds of the DesksBarView, in this
// case we scale down the item, and center it around the drag location. // case we scale down the item, and center it around the drag location.
bounds.set_size(on_desks_bar_item_size_); bounds.set_size(on_desks_bar_item_size_);
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_features.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/test/ash_test_base.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/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_grid.h"
...@@ -198,4 +201,80 @@ TEST_F(OverviewWindowDragControllerTest, NoDragToCloseUsingMouse) { ...@@ -198,4 +201,80 @@ TEST_F(OverviewWindowDragControllerTest, NoDragToCloseUsingMouse) {
EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds()); 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 } // 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