1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
ash / shelf / drag_window_from_shelf_controller.h [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SHELF_DRAG_WINDOW_FROM_SHELF_CONTROLLER_H_
#define ASH_SHELF_DRAG_WINDOW_FROM_SHELF_CONTROLLER_H_
#include <cstdint>
#include <optional>
#include <vector>
#include "ash/ash_export.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/shelf/shelf_metrics.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_types.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/timer/timer.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_tree_owner.h"
namespace aura {
class Window;
} // namespace aura
namespace gfx {
class PointF;
} // namespace gfx
namespace ash {
// The window drag controller that will be used when a window is dragged up by
// swiping up from the shelf to homescreen, overview or splitview.
class ASH_EXPORT DragWindowFromShelfController : public aura::WindowObserver {
public:
// The deceleration threshold to open overview behind the dragged window
// when swiping up from the shelf to drag the active window.
static constexpr float kOpenOverviewThreshold = 10.f;
// The deceleration threshold to show or hide overview during window dragging
// when dragging a window up from the shelf.
static constexpr float kShowOverviewThreshold = 50.f;
// The upward velocity threshold to take the user to the home launcher screen
// when swiping up from the shelf. Can happen anytime during dragging.
static constexpr float kVelocityToHomeScreenThreshold = 1000.f;
// When swiping up from the shelf, the user can continue dragging and end with
// a downward fling. This is the downward velocity threshold required to
// restore the original window bounds.
static constexpr float kVelocityToRestoreBoundsThreshold = 1000.f;
// The upward velocity threshold to fling the window into overview when split
// view is active during dragging.
static constexpr float kVelocityToOverviewThreshold = 1000.f;
// If the window drag starts within |kDistanceFromEdge| from screen edge, it
// will get snapped if the drag ends in the snap region, no matter how far
// the window has been dragged.
static constexpr int kDistanceFromEdge = 8;
// A window has to be dragged toward the direction of the edge of the screen
// for a minimum of |kMinDragDistance| to a point within
// |kScreenEdgeInsetForSnap| of the edge of the screen, or dragged inside
// |kDistanceFromEdge| from edge to be snapped.
static constexpr int kScreenEdgeInsetForSnap = 48;
static constexpr int kMinDragDistance = 96;
// The distance for the dragged window to pass over the bottom of the display
// so that it can be dragged into home launcher or overview. If not pass this
// value (the top of the hotseat), the window will snap back to its original
// position. The value is different for standard or dense shelf.
static float GetReturnToMaximizedThreshold();
DragWindowFromShelfController(aura::Window* window,
const gfx::PointF& location_in_screen);
DragWindowFromShelfController(const DragWindowFromShelfController&) = delete;
DragWindowFromShelfController& operator=(
const DragWindowFromShelfController&) = delete;
~DragWindowFromShelfController() override;
// Called during swiping up on the shelf.
void Drag(const gfx::PointF& location_in_screen,
float scroll_x,
float scroll_y);
std::optional<ShelfWindowDragResult> EndDrag(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y);
void CancelDrag();
bool IsDraggedWindowAnimating() const;
// Performs the action on the dragged window depending on
// |window_drag_result_|, such as scaling up/down the dragged window. This
// method should be called after EndDrag() which computes
// |window_drag_result_|.
void FinalizeDraggedWindow();
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
aura::Window* dragged_window() { return window_; }
bool drag_started() const { return drag_started_; }
bool during_window_restoration() const { return during_window_restoration_; }
private:
class WindowsHider;
friend class DragWindowFromShelfControllerTestApi;
void OnDragStarted(const gfx::PointF& location_in_screen);
void OnDragEnded(const gfx::PointF& location_in_screen,
bool should_drop_window_in_overview,
SnapPosition snap_position);
// Updates the dragged window's transform during dragging.
void UpdateDraggedWindow(const gfx::PointF& location_in_screen);
// Returns the desired snap position on |location_in_screen| during dragging.
SnapPosition GetSnapPosition(const gfx::PointF& location_in_screen) const;
// Returns true if the dragged window should restore to its original bounds
// after drag ends. Happens when the bottom of the dragged window is
// within the GetReturnToMaximizedThreshold() threshold, or when the downward
// vertical velocity is larger than kVelocityToRestoreBoundsThreshold.
bool ShouldRestoreToOriginalBounds(const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const;
// Returns true if we should go to home screen after drag ends. Happens when
// the upward vertical velocity is larger than kVelocityToHomeScreenThreshold
// and splitview is not active. Note when splitview is active, we do not allow
// to go to home screen by fling.
bool ShouldGoToHomeScreen(const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const;
// Returns the desired snap position on |location_in_screen| when drag ends.
SnapPosition GetSnapPositionOnDragEnd(const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const;
// Returns true if we should drop the dragged window in overview after drag
// ends.
bool ShouldDropWindowInOverview(const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const;
// Reshows the windows that were hidden before drag starts.
void ReshowHiddenWindowsOnDragEnd();
// Calls when the user resumes or ends window dragging. Overview should show
// up and split view indicators should be updated.
void ShowOverviewDuringOrAfterDrag();
// Overview should be hidden when the user drags the window quickly up or
// around.
void HideOverviewDuringDrag();
// Called when the dragged window should scale down and fade out to home
// screen after drag ends.
void ScaleDownWindowAfterDrag();
// Callback function to be called after the window has been scaled down and
// faded out after drag ends.
void OnWindowScaledDownAfterDrag();
// Called when the dragged window should scale up to restore to its original
// bounds after drag ends.
void ScaleUpToRestoreWindowAfterDrag();
// Callback function to be called after the window has been restored to its
// original bounds after drag ends.
void OnWindowRestoredToOriginalBounds(bool end_overview);
// Called to do proper initialization in overview for the dragged window. The
// function is supposed to be called with an active overview session.
void OnWindowDragStartedInOverview();
// Cleans up `other_window_` and `other_window_copy_`.
// If `show` is `std::nullopt`, we destroy the copy without animation.
// If `show` is true, drag has been canceled and we scale up the copy and fade
// it in. The copy will be destroyed and replaced by the original window on
// animation end.
// If `show` is false, fade out the copy and destroy it after the animation.
void ResetOtherWindow(std::optional<bool> show);
raw_ptr<aura::Window> window_ = nullptr;
// The `other_window_` refers to the window other than `window_` that is
// visible while `window_` is being dragged. This happens when there is a
// floated window.
raw_ptr<aura::Window> other_window_ = nullptr;
std::unique_ptr<ui::LayerTreeOwner> other_window_copy_;
gfx::PointF initial_location_in_screen_;
gfx::PointF previous_location_in_screen_;
bool drag_started_ = false;
// Whether overview was active when the drag started.
bool started_in_overview_ = false;
// Hide all eligible windows during window dragging. Depends on different
// scenarios, we may or may not reshow there windows when drag ends.
std::unique_ptr<WindowsHider> windows_hider_;
// Timer to show and update overview.
base::OneShotTimer show_overview_timer_;
// True if overview is active and its windows are showing.
bool show_overview_windows_ = false;
// A pending action from EndDrag() to be performed in FinalizeDraggedWindow().
std::optional<ShelfWindowDragResult> window_drag_result_;
// True while we are restoring windows back to their original bounds after a
// drag (i.e. dragged tiny amount from shelf).
bool during_window_restoration_ = false;
base::OnceClosure on_overview_shown_callback_for_testing_;
SnapPosition initial_snap_position_ = SnapPosition::kNone;
SnapPosition end_snap_position_ = SnapPosition::kNone;
std::unique_ptr<ui::PresentationTimeRecorder> presentation_time_recorder_;
// Pointer to the last `OverviewSession` that was started by a window drag.
// Null by default, or if an overview session was started by other means.
base::WeakPtr<OverviewSession> last_overview_drag_session_ptr_;
base::WeakPtrFactory<DragWindowFromShelfController> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_SHELF_DRAG_WINDOW_FROM_SHELF_CONTROLLER_H_