Commit 047b6d71 authored by Xiaoqian Dai's avatar Xiaoqian Dai Committed by Commit Bot

overview gesture: Swipe up from shelf to drag the active window around.

See https://docs.google.com/document/d/1rskVuhK9wAqgntcq9WYPSknMEc_jsAp3zrqb4YSMAqE/edit#
for the mock and expected behaviors.

See crbug.com/997885#c5 for demo. For now with this CL in place, we can
only drag the window around. More will be done in follow up Cls.

Bug: 997885
Change-Id: Iecea3a8cb4a6fe3c6a64ddddea08bc010cfb72dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1817105
Commit-Queue: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#700306}
parent f589d580
......@@ -5,11 +5,12 @@
#include "ash/home_screen/home_launcher_gesture_handler.h"
#include <algorithm>
#include <memory>
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/home_screen/home_launcher_gesture_handler_observer.h"
#include "ash/home_screen/home_screen_controller.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/root_window_controller.h"
#include "ash/scoped_animation_disabler.h"
#include "ash/screen_util.h"
......@@ -17,6 +18,7 @@
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_divider.h"
#include "ash/wm/window_state.h"
......@@ -30,11 +32,13 @@
#include "base/metrics/user_metrics.h"
#include "base/numerics/ranges.h"
#include "ui/aura/client/window_types.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/transform_util.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/transient_window_manager.h"
#include "ui/wm/core/window_util.h"
......@@ -59,6 +63,9 @@ constexpr int kScrollVelocityThreshold = 6;
// this ratio.
constexpr float kWidthRatio = 0.8f;
// The minimum window scale factor when dragging a window from shelf.
constexpr float kMinimumWindowScaleDuringDragging = 0.2f;
bool IsTabletMode() {
return Shell::Get()->tablet_mode_controller()->InTabletMode();
}
......@@ -69,8 +76,12 @@ bool CanProcessWindow(aura::Window* window,
if (!window)
return false;
if (!IsTabletMode())
return false;
if (!window->IsVisible() &&
mode == HomeLauncherGestureHandler::Mode::kSlideUpToShow) {
(mode == HomeLauncherGestureHandler::Mode::kSlideUpToShow ||
mode == HomeLauncherGestureHandler::Mode::kDragWindowToHomeOrOverview)) {
return false;
}
......@@ -79,9 +90,6 @@ bool CanProcessWindow(aura::Window* window,
return false;
}
if (!IsTabletMode())
return false;
if (window->type() == aura::client::WINDOW_TYPE_POPUP)
return false;
......@@ -166,6 +174,49 @@ HomeScreenDelegate* GetHomeScreenDelegate() {
return Shell::Get()->home_screen_controller()->delegate();
}
// Returns the window to be dragged into home screen or overview. Only used in
// HomeLauncherGestureHandler::Mode::kDragWindowToHomeOrOverview mode.
aura::Window* GetWindowForDragToHomeOrOverview(
const gfx::Point& location_in_screen,
const std::vector<aura::Window*>& mru_windows) {
if (!IsTabletMode())
return nullptr;
if (mru_windows.empty())
return nullptr;
aura::Window* window = nullptr;
SplitViewController* split_view_controller =
Shell::Get()->split_view_controller();
const bool is_in_splitview = split_view_controller->InSplitViewMode();
const bool is_in_overview =
Shell::Get()->overview_controller()->InOverviewSession();
if (!is_in_splitview && !is_in_overview) {
// If split view mode is not active, use the first MRU window.
window = mru_windows[0];
} else if (is_in_splitview) {
// If split view mode is active, use the event location to decide which
// window should be the dragged window.
aura::Window* left_window = split_view_controller->left_window();
aura::Window* right_window = split_view_controller->right_window();
const int divider_position = split_view_controller->divider_position();
const bool is_landscape = IsCurrentScreenOrientationLandscape();
const bool is_primary = IsCurrentScreenOrientationPrimary();
const gfx::Rect work_area =
screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
split_view_controller->GetDefaultSnappedWindow());
if (is_landscape) {
if (location_in_screen.x() < work_area.x() + divider_position)
window = is_primary ? left_window : right_window;
else
window = is_primary ? right_window : left_window;
} else {
window = is_primary ? right_window : left_window;
}
}
return window;
}
} // namespace
// Class which allows us to make modifications to a window, and removes those
......@@ -271,6 +322,102 @@ class HomeLauncherGestureHandler::ScopedWindowModifier
DISALLOW_COPY_AND_ASSIGN(ScopedWindowModifier);
};
// The window drag controller for a window that's being dragging from swiping
// up from the shelf.
class HomeLauncherGestureHandler::DragWindowFromShelfController {
public:
explicit DragWindowFromShelfController(aura::Window* window)
: window_(window) {}
~DragWindowFromShelfController() { EndDrag(gfx::Point()); }
// Called during swiping up on the shelf.
void Drag(const gfx::Point& location_in_screen) {
if (!drag_started_) {
// Do not start drag until the drag goes above the shelf.
const gfx::Rect work_area =
screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
window_);
if (location_in_screen.y() > work_area.bottom())
return;
OnDragStarted(location_in_screen);
}
UpdateDraggedWindow(location_in_screen);
}
void EndDrag(const gfx::Point& location_in_screen) {
if (!drag_started_)
return;
drag_started_ = false;
WindowState::Get(window_)->DeleteDragDetails();
SetTransform(window_, gfx::Transform());
window_->SetProperty(kBackdropWindowMode, original_backdrop_mode_);
// Re-show the home launcher after drag ends.
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
aura::Window* home_screen_window =
home_screen_delegate->GetHomeScreenWindow();
DCHECK(home_screen_window);
home_screen_window->Show();
}
private:
void OnDragStarted(const gfx::Point& location_in_screen) {
drag_started_ = true;
initial_location_in_screen_ = location_in_screen;
WindowState::Get(window_)->CreateDragDetails(
initial_location_in_screen_, HTCLIENT, ::wm::WINDOW_MOVE_SOURCE_TOUCH);
// Disable the backdrop on the dragged window during dragging.
original_backdrop_mode_ = window_->GetProperty(kBackdropWindowMode);
window_->SetProperty(kBackdropWindowMode, BackdropWindowMode::kDisabled);
// Hide the home launcher until it's eligible to show it.
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
aura::Window* home_screen_window =
home_screen_delegate->GetHomeScreenWindow();
DCHECK(home_screen_window);
home_screen_window->Hide();
}
void UpdateDraggedWindow(const gfx::Point& location_in_screen) {
gfx::Rect bounds = window_->bounds();
::wm::ConvertRectToScreen(window_->parent(), &bounds);
// Calculate the window's transform based on the location.
// For scale, at |initial_location_in_screen_|, the scale is 1.0, and at the
// middle y position of its bounds, it reaches to its minimum scale 0.2.
// Calculate the desired scale based on the current y position.
int y_full = bounds.bottom() - bounds.CenterPoint().y();
int y_diff = location_in_screen.y() - bounds.CenterPoint().y();
float scale = (1.0f - kMinimumWindowScaleDuringDragging) * y_diff / y_full +
kMinimumWindowScaleDuringDragging;
scale = base::ClampToRange(scale, /*min=*/kMinimumWindowScaleDuringDragging,
/*max=*/1.f);
// Calculate the desired translation so that the dragged window stays under
// the finger during the dragging.
gfx::Transform transform;
transform.Translate(
(location_in_screen.x() - bounds.x()) -
(initial_location_in_screen_.x() - bounds.x()) * scale,
(location_in_screen.y() - bounds.y()) -
(initial_location_in_screen_.y() - bounds.y()) * scale);
transform.Scale(scale, scale);
SetTransform(window_, transform);
}
aura::Window* const window_;
gfx::Point initial_location_in_screen_;
bool drag_started_ = false;
BackdropWindowMode original_backdrop_mode_ = BackdropWindowMode::kAuto;
DISALLOW_COPY_AND_ASSIGN(DragWindowFromShelfController);
};
HomeLauncherGestureHandler::HomeLauncherGestureHandler() {
tablet_mode_observer_.Add(Shell::Get()->tablet_mode_controller());
}
......@@ -289,22 +436,13 @@ bool HomeLauncherGestureHandler::OnPressEvent(Mode mode,
if (!display_.is_valid())
return false;
if (!SetUpWindows(mode, /*window=*/nullptr))
if (!SetUpWindows(mode, /*window=*/nullptr, location))
return false;
mode_ = mode;
last_event_location_ = base::make_optional(location);
if (mode != Mode::kNone) {
NotifyHomeLauncherTargetPositionChanged(
mode == Mode::kSlideUpToShow /*showing*/, display_.id());
}
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
home_screen_delegate->OnHomeLauncherDragStart();
UpdateWindows(0.0, /*animate=*/false);
OnDragStarted(location);
return true;
}
......@@ -321,12 +459,7 @@ bool HomeLauncherGestureHandler::OnScrollEvent(const gfx::Point& location,
DCHECK(display_.is_valid());
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
home_screen_delegate->OnHomeLauncherDragInProgress();
UpdateWindows(GetHeightInWorkAreaAsRatio(location, display_.work_area()),
/*animate=*/false);
OnDragContinued(location);
return true;
}
......@@ -334,30 +467,7 @@ bool HomeLauncherGestureHandler::OnReleaseEvent(const gfx::Point& location) {
if (IsAnimating())
return false;
// In clamshell mode, AppListView::SetIsInDrag is called explicitly so it
// does not need the notification from HomeLauncherGestureHandler.
if (IsTabletMode()) {
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
home_screen_delegate->OnHomeLauncherDragEnd();
}
if (!IsDragInProgress()) {
if (GetActiveWindow()) {
// |active_window_| may not be nullptr when this release event is
// triggered by opening |active_window_| with modal dialog in
// OnPressEvent(). In that case, just leave the |active_window_| in show
// state and stop tracking.
AnimateToFinalState(AnimationTrigger::kDragRelease);
RemoveObserversAndStopTracking();
return true;
}
return false;
}
last_event_location_ = base::make_optional(location);
AnimateToFinalState(AnimationTrigger::kDragRelease);
return true;
return OnDragEnded(location);
}
void HomeLauncherGestureHandler::Cancel() {
......@@ -380,13 +490,15 @@ bool HomeLauncherGestureHandler::ShowHomeLauncher(
if (!display.is_valid())
return false;
if (!SetUpWindows(Mode::kSlideUpToShow, /*window=*/nullptr))
if (!SetUpWindows(Mode::kSlideUpToShow, /*window=*/nullptr,
/*location_in_screen=*/base::nullopt)) {
return false;
}
display_ = display;
mode_ = Mode::kSlideUpToShow;
UpdateWindows(0.0, /*animate=*/false);
UpdateWindowsForSlideUpOrDown(0.0, /*animate=*/false);
AnimateToFinalState(AnimationTrigger::kLauncherButton);
return true;
}
......@@ -400,13 +512,15 @@ bool HomeLauncherGestureHandler::HideHomeLauncherForWindow(
if (!display.is_valid())
return false;
if (!SetUpWindows(Mode::kSlideDownToHide, window))
if (!SetUpWindows(Mode::kSlideDownToHide, window,
/*location_in_screen=*/base::nullopt)) {
return false;
}
display_ = display;
mode_ = Mode::kSlideDownToHide;
UpdateWindows(1.0, /*animate=*/false);
UpdateWindowsForSlideUpOrDown(1.0, /*animate=*/false);
AnimateToFinalState(AnimationTrigger::kHideForWindow);
return true;
}
......@@ -453,6 +567,7 @@ void HomeLauncherGestureHandler::OnWindowDestroying(aura::Window* window) {
hidden_window->Show();
RemoveObserversAndStopTracking();
window_drag_controller_.reset();
return;
}
......@@ -480,7 +595,8 @@ void HomeLauncherGestureHandler::OnTabletModeEnded() {
active_window_->StopAnimating();
if (secondary_window_)
secondary_window_->StopAnimating();
UpdateWindows(IsFinalStateShow() ? 1.0 : 0.0, /*animate=*/false);
UpdateWindowsForSlideUpOrDown(IsFinalStateShow() ? 1.0 : 0.0,
/*animate=*/false);
OnImplicitAnimationsCompleted();
}
......@@ -566,7 +682,8 @@ void HomeLauncherGestureHandler::AnimateToFinalState(AnimationTrigger trigger) {
const bool is_final_state_show = IsFinalStateShow();
GetHomeScreenDelegate()->NotifyHomeLauncherAnimationTransition(
trigger, is_final_state_show);
UpdateWindows(is_final_state_show ? 1.0 : 0.0, /*animate=*/true);
UpdateWindowsForSlideUpOrDown(is_final_state_show ? 1.0 : 0.0,
/*animate=*/true);
if (!is_final_state_show && mode_ == Mode::kSlideDownToHide) {
NotifyHomeLauncherTargetPositionChanged(false /*showing*/, display_.id());
......@@ -596,7 +713,8 @@ void HomeLauncherGestureHandler::UpdateSettings(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
}
void HomeLauncherGestureHandler::UpdateWindows(double progress, bool animate) {
void HomeLauncherGestureHandler::UpdateWindowsForSlideUpOrDown(double progress,
bool animate) {
// Update full screen applist.
DCHECK(display_.is_valid());
const gfx::Rect work_area = display_.work_area();
......@@ -768,7 +886,10 @@ bool HomeLauncherGestureHandler::IsFinalStateShow() {
: mode_ == Mode::kSlideUpToShow;
}
bool HomeLauncherGestureHandler::SetUpWindows(Mode mode, aura::Window* window) {
bool HomeLauncherGestureHandler::SetUpWindows(
Mode mode,
aura::Window* window,
base::Optional<gfx::Point> location_in_screen) {
SplitViewController* split_view_controller =
Shell::Get()->split_view_controller();
overview_active_on_gesture_start_ =
......@@ -795,18 +916,26 @@ bool HomeLauncherGestureHandler::SetUpWindows(Mode mode, aura::Window* window) {
if (IsTabletMode() && overview_active_on_gesture_start_ &&
!split_view_active) {
DCHECK_EQ(Mode::kSlideUpToShow, mode);
DCHECK(mode == Mode::kSlideUpToShow ||
mode == Mode::kDragWindowToHomeOrOverview);
active_window_.reset();
return true;
}
// Always hide split view windows if they exist. Otherwise, hide the
// specified window if it is not null. If none of above is true, we want
// the first window in the mru list, if it exists and is usable.
aura::Window* first_window =
split_view_active
? split_view_controller->GetDefaultSnappedWindow()
: (window ? window : (windows.empty() ? nullptr : windows[0]));
aura::Window* first_window = nullptr;
if (mode == HomeLauncherGestureHandler::Mode::kDragWindowToHomeOrOverview) {
DCHECK(location_in_screen.has_value());
first_window =
GetWindowForDragToHomeOrOverview(*location_in_screen, windows);
} else {
// Always hide split view windows if they exist. Otherwise, hide the
// specified window if it is not null. If none of above is true, we want
// the first window in the mru list, if it exists and is usable.
first_window =
split_view_active
? split_view_controller->GetDefaultSnappedWindow()
: (window ? window : (windows.empty() ? nullptr : windows[0]));
}
if (!CanProcessWindow(first_window, mode)) {
active_window_.reset();
return false;
......@@ -899,12 +1028,18 @@ bool HomeLauncherGestureHandler::SetUpWindows(Mode mode, aura::Window* window) {
}
// Hide all visible windows which are behind our window so that when we
// scroll, the home launcher will be visible. This is only needed when
// swiping up, and not when overview mode is active.
// scroll, the home launcher will be visible in kSlideUpToShow case and
// wallpaper will be visible in kDragWindowToHomeOrOverview case. This is only
// needed when swiping up, and not when overview mode is active.
hidden_windows_.clear();
if (mode == Mode::kSlideUpToShow && !overview_active_on_gesture_start_) {
if ((mode == Mode::kSlideUpToShow ||
mode == Mode::kDragWindowToHomeOrOverview) &&
!overview_active_on_gesture_start_) {
for (auto* window : windows) {
if (window->IsVisible()) {
if (window->IsVisible() &&
(mode == Mode::kSlideUpToShow ||
(mode == Mode::kDragWindowToHomeOrOverview &&
!split_view_controller->IsWindowInSplitView(window)))) {
hidden_windows_.push_back(window);
window->AddObserver(this);
}
......@@ -916,4 +1051,75 @@ bool HomeLauncherGestureHandler::SetUpWindows(Mode mode, aura::Window* window) {
return true;
}
void HomeLauncherGestureHandler::OnDragStarted(const gfx::Point& location) {
if (mode_ == Mode::kDragWindowToHomeOrOverview) {
window_drag_controller_ =
std::make_unique<DragWindowFromShelfController>(GetActiveWindow());
} else {
NotifyHomeLauncherTargetPositionChanged(
mode_ == Mode::kSlideUpToShow /*showing*/, display_.id());
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
home_screen_delegate->OnHomeLauncherDragStart();
UpdateWindowsForSlideUpOrDown(/*progress=*/0.0, /*animate=*/false);
}
}
void HomeLauncherGestureHandler::OnDragContinued(const gfx::Point& location) {
if (mode_ == Mode::kDragWindowToHomeOrOverview) {
window_drag_controller_->Drag(location);
} else {
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
home_screen_delegate->OnHomeLauncherDragInProgress();
UpdateWindowsForSlideUpOrDown(
GetHeightInWorkAreaAsRatio(location, display_.work_area()),
/*animate=*/false);
}
}
bool HomeLauncherGestureHandler::OnDragEnded(const gfx::Point& location) {
if (mode_ == Mode::kDragWindowToHomeOrOverview) {
last_event_location_ = base::make_optional(location);
// Reshow all windows previously hidden before dragging.
for (auto* window : hidden_windows_) {
ScopedAnimationDisabler disable(window);
window->Show();
}
window_drag_controller_->EndDrag(location);
RemoveObserversAndStopTracking();
} else {
// In clamshell mode, AppListView::SetIsInDrag is called explicitly so it
// does not need the notification from HomeLauncherGestureHandler.
if (IsTabletMode()) {
HomeScreenDelegate* home_screen_delegate = GetHomeScreenDelegate();
DCHECK(home_screen_delegate);
home_screen_delegate->OnHomeLauncherDragEnd();
}
if (!IsDragInProgress()) {
if (GetActiveWindow()) {
// |active_window_| may not be nullptr when this release event is
// triggered by opening |active_window_| with modal dialog in
// OnPressEvent(). In that case, just leave the |active_window_| in
// show state and stop tracking.
AnimateToFinalState(AnimationTrigger::kDragRelease);
RemoveObserversAndStopTracking();
return true;
}
return false;
}
last_event_location_ = base::make_optional(location);
AnimateToFinalState(AnimationTrigger::kDragRelease);
}
return true;
}
} // namespace ash
......@@ -6,6 +6,7 @@
#define ASH_HOME_SCREEN_HOME_LAUNCHER_GESTURE_HANDLER_H_
#include <map>
#include <memory>
#include <vector>
#include "ash/ash_export.h"
......@@ -42,6 +43,11 @@ class ASH_EXPORT HomeLauncherGestureHandler
// Sliding up the MRU window to display launcher. If in overview mode,
// slides up overview mode as well.
kSlideUpToShow,
// Sliding up from the shelf to drag the MRU window (or one of the snapped
// window in splitview) around to enter either home launcher screen or to
// overview screen. If in overview mode, this mode is a no-op. Note: This
// mode is behind the feature flag kDragFromShelfToHomeOrOverview.
kDragWindowToHomeOrOverview,
// Sliding down the MRU window to hide launcher.
kSlideDownToHide,
};
......@@ -95,6 +101,8 @@ class ASH_EXPORT HomeLauncherGestureHandler
private:
class ScopedWindowModifier;
class DragWindowFromShelfController;
FRIEND_TEST_ALL_PREFIXES(HomeLauncherModeGestureHandlerTest,
AnimatingToEndResetsState);
......@@ -119,8 +127,9 @@ class ASH_EXPORT HomeLauncherGestureHandler
// on the values in |window_values_| and |transient_descendants_values_|.
// |progress| is between 0.0 and 1.0, where 0.0 means the window will have its
// original opacity and transform, and 1.0 means the window will be faded out
// and transformed offscreen.
void UpdateWindows(double progress, bool animate);
// and transformed offscreen. This function is used by kSlideUpToShow and
// kSlideDownToHide mode.
void UpdateWindowsForSlideUpOrDown(double progress, bool animate);
// Stop observing all windows and remove their local pointers.
void RemoveObserversAndStopTracking();
......@@ -137,9 +146,19 @@ class ASH_EXPORT HomeLauncherGestureHandler
// Sets up windows that will be used in dragging and animation. If |window| is
// not null for kSlideDownToHide mode, it will be set as the window to run
// slide down animation. |window| is not used for kSlideUpToShow mode. Returns
// true if windows are successfully set up.
bool SetUpWindows(Mode mode, aura::Window* window);
// slide down animation. |window| is not used for kSlideUpToShow or
// kDragWindowToHomeOrOverview mode. |location_in_screen| is only used for
// kDragWindowToHomeOrOverview mode to find the eligible widnow to drag.
// Returns true if windows are successfully set up.
bool SetUpWindows(Mode mode,
aura::Window* window,
base::Optional<gfx::Point> location_in_screen);
// Called by OnPress/Scroll/ReleaseEvent() when the drag from the shelf or
// from the top starts/continues/ends. |location| is in screen coordinate.
void OnDragStarted(const gfx::Point& location);
void OnDragContinued(const gfx::Point& location);
bool OnDragEnded(const gfx::Point& location);
Mode mode_ = Mode::kNone;
......@@ -187,6 +206,10 @@ class ASH_EXPORT HomeLauncherGestureHandler
// The display where the windows are being processed.
display::Display display_;
// The window drag controller that will be used in kDragWindowToHomeOrOverview
// mode. Will not be created in other modes.
std::unique_ptr<DragWindowFromShelfController> window_drag_controller_;
base::ObserverList<HomeLauncherGestureHandlerObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(HomeLauncherGestureHandler);
......
......@@ -426,6 +426,117 @@ TEST_F(HomeLauncherGestureHandlerTest, TransparentShelfWileDragging) {
->GetShelfBackgroundType());
}
// Tests that in kDragWindowToHomeOrOverview mode, the dragged active window
// might be different in different scenarios.
TEST_F(HomeLauncherGestureHandlerTest, DraggedActiveWindow) {
const gfx::Rect shelf_bounds =
Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
// We need at least one window to work with.
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.CenterPoint());
EXPECT_FALSE(GetGestureHandler()->GetActiveWindow());
auto window1 = CreateWindowForTesting();
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.CenterPoint());
EXPECT_EQ(GetGestureHandler()->GetActiveWindow(), window1.get());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.CenterPoint());
EXPECT_FALSE(GetGestureHandler()->GetActiveWindow());
// Test in splitview, depends on the drag position, the active dragged window
// might be different.
auto window2 = CreateWindowForTesting();
SplitViewController* split_view_controller =
Shell::Get()->split_view_controller();
split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.bottom_left());
EXPECT_EQ(GetGestureHandler()->GetActiveWindow(), window1.get());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.bottom_left());
EXPECT_FALSE(GetGestureHandler()->GetActiveWindow());
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.bottom_right());
EXPECT_EQ(GetGestureHandler()->GetActiveWindow(), window2.get());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.bottom_right());
EXPECT_FALSE(GetGestureHandler()->GetActiveWindow());
split_view_controller->EndSplitView();
// In overview, drag from shelf is a no-op.
Shell::Get()->overview_controller()->StartOverview();
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.CenterPoint());
EXPECT_FALSE(GetGestureHandler()->GetActiveWindow());
}
// Tests that in kDragWindowToHomeOrOverview mode, we may hide different sets
// of windows in different scenarios.
TEST_F(HomeLauncherGestureHandlerTest, HideWindowDuringWindowDragging) {
const gfx::Rect shelf_bounds =
Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
auto window3 = CreateWindowForTesting();
auto window2 = CreateWindowForTesting();
auto window1 = CreateWindowForTesting();
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.CenterPoint());
EXPECT_TRUE(window1->IsVisible());
EXPECT_FALSE(window2->IsVisible());
EXPECT_FALSE(window3->IsVisible());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.CenterPoint());
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
// In splitview mode, the snapped windows will stay visible during dragging.
SplitViewController* split_view_controller =
Shell::Get()->split_view_controller();
split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.bottom_left());
EXPECT_EQ(GetGestureHandler()->GetActiveWindow(), window1.get());
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_FALSE(window3->IsVisible());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.bottom_left());
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.bottom_right());
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_FALSE(window3->IsVisible());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.bottom_right());
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
}
TEST_F(HomeLauncherGestureHandlerTest, HideHomeLauncherDuringDraggingTest) {
UpdateDisplay("400x400");
const gfx::Rect shelf_bounds =
Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
auto window = CreateWindowForTesting();
GetGestureHandler()->OnPressEvent(Mode::kDragWindowToHomeOrOverview,
shelf_bounds.CenterPoint());
GetGestureHandler()->OnScrollEvent(gfx::Point(0, 300), 1.f);
aura::Window* home_screen_window =
Shell::Get()->home_screen_controller()->delegate()->GetHomeScreenWindow();
EXPECT_TRUE(home_screen_window);
EXPECT_FALSE(home_screen_window->IsVisible());
GetGestureHandler()->OnReleaseEvent(shelf_bounds.CenterPoint());
EXPECT_TRUE(home_screen_window->IsVisible());
}
class HomeLauncherModeGestureHandlerTest
: public HomeLauncherGestureHandlerTest,
public testing::WithParamInterface<Mode> {
......
......@@ -96,6 +96,9 @@ const base::Feature kEnableBackgroundBlur{"EnableBackgroundBlur",
const base::Feature kSwipingFromLeftEdgeToGoBack{
"SwipingFromLeftEdgeToGoBack", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kDragFromShelfToHomeOrOverview{
"DragFromShelfToHomeOrOverview", base::FEATURE_DISABLED_BY_DEFAULT};
bool IsHideArcMediaNotificationsEnabled() {
return base::FeatureList::IsEnabled(kMediaSessionNotification) &&
base::FeatureList::IsEnabled(kHideArcMediaNotifications);
......@@ -181,5 +184,9 @@ bool IsSwipingFromLeftEdgeToGoBackEnabled() {
return base::FeatureList::IsEnabled(kSwipingFromLeftEdgeToGoBack);
}
bool IsDragFromShelfToHomeOrOverviewEnabled() {
return base::FeatureList::IsEnabled(kDragFromShelfToHomeOrOverview);
}
} // namespace features
} // namespace ash
......@@ -125,6 +125,12 @@ ASH_PUBLIC_EXPORT extern const base::Feature kUnifiedMessageCenterRefactor;
// display. Only for tablet mode.
ASH_PUBLIC_EXPORT extern const base::Feature kSwipingFromLeftEdgeToGoBack;
// Enables dragging from shelf to enter home screen or overview feature.
// Only for tablet mode.
// TODO(https://crbug.com/992642): Remove this after this feature is fully
// launched.
ASH_PUBLIC_EXPORT extern const base::Feature kDragFromShelfToHomeOrOverview;
ASH_PUBLIC_EXPORT bool IsHideArcMediaNotificationsEnabled();
ASH_PUBLIC_EXPORT bool IsKeyboardShortcutViewerAppEnabled();
......@@ -165,6 +171,8 @@ ASH_PUBLIC_EXPORT bool IsBackgroundBlurEnabled();
ASH_PUBLIC_EXPORT bool IsSwipingFromLeftEdgeToGoBackEnabled();
ASH_PUBLIC_EXPORT bool IsDragFromShelfToHomeOrOverviewEnabled();
} // namespace features
} // namespace ash
......
......@@ -166,7 +166,7 @@ class HideAnimationObserver : public ui::ImplicitAnimationObserver {
class HotseatEventHandler : public ui::EventHandler,
public ShelfLayoutManagerObserver {
public:
HotseatEventHandler(ShelfLayoutManager* shelf_layout_manager)
explicit HotseatEventHandler(ShelfLayoutManager* shelf_layout_manager)
: shelf_layout_manager_(shelf_layout_manager) {
shelf_layout_manager_->AddObserver(this);
Shell::Get()->AddPreTargetHandler(this);
......@@ -1829,9 +1829,12 @@ bool ShelfLayoutManager::StartGestureDrag(
drag_status_ = kDragAppListInProgress;
HomeLauncherGestureHandler* home_launcher_handler =
Shell::Get()->home_screen_controller()->home_launcher_gesture_handler();
if (home_launcher_handler->OnPressEvent(
HomeLauncherGestureHandler::Mode::kSlideUpToShow,
gesture_in_screen.location())) {
HomeLauncherGestureHandler::Mode slide_mode =
features::IsDragFromShelfToHomeOrOverviewEnabled()
? HomeLauncherGestureHandler::Mode::kDragWindowToHomeOrOverview
: HomeLauncherGestureHandler::Mode::kSlideUpToShow;
if (home_launcher_handler->OnPressEvent(slide_mode,
gesture_in_screen.location())) {
return true;
}
drag_status_ = previous_drag_status;
......@@ -1889,7 +1892,7 @@ void ShelfLayoutManager::UpdateMouseDrag(
if (drag_status_ == kDragAttempt) {
// Do not start drag for the small offset.
if (abs(mouse_in_screen.location().y() - last_mouse_drag_position_.y()) <
kMouseDragThreshold) {
kMouseDragThreshold) {
return;
}
......
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