1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
6 #define ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
7 
8 #include <memory>
9 
10 #include "ash/ash_export.h"
11 #include "ash/wm/splitview/split_view_controller.h"
12 #include "base/containers/flat_map.h"
13 #include "base/macros.h"
14 #include "ui/gfx/geometry/point_f.h"
15 
16 namespace ash {
17 
18 class OverviewGrid;
19 class OverviewItem;
20 class OverviewSession;
21 class PresentationTimeRecorder;
22 
23 // These values are persisted to logs. Entries should not be renumbered and
24 // numeric values should never be reused.
25 // Workflows of dragging windows from overview (not from the top or shelf).
26 enum class OverviewDragAction {
27   kToGridSameDisplayClamshellMouse = 0,
28   kToGridSameDisplayClamshellTouch = 1,
29   kToDeskSameDisplayClamshellMouse = 2,
30   kToDeskSameDisplayClamshellTouch = 3,
31   kToSnapSameDisplayClamshellMouse = 4,
32   kToSnapSameDisplayClamshellTouch = 5,
33   kSwipeToCloseSuccessfulClamshellTouch = 6,
34   kSwipeToCloseCanceledClamshellTouch = 7,
35   kFlingToCloseClamshellTouch = 8,
36   kToGridOtherDisplayClamshellMouse = 9,
37   kToDeskOtherDisplayClamshellMouse = 10,
38   kToSnapOtherDisplayClamshellMouse = 11,
39   kToGridSameDisplayTabletTouch = 12,
40   kToDeskSameDisplayTabletTouch = 13,
41   kToSnapSameDisplayTabletTouch = 14,
42   kSwipeToCloseSuccessfulTabletTouch = 15,
43   kSwipeToCloseCanceledTabletTouch = 16,
44   kFlingToCloseTabletTouch = 17,
45   kMaxValue = kFlingToCloseTabletTouch,
46 };
47 
48 // The drag controller for an overview window item in overview mode. It updates
49 // the position of the corresponding window item using transform while dragging.
50 // It also updates the split view drag indicators, which handles showing
51 // indicators where to drag, and preview areas showing the bounds of the
52 // window about to be snapped.
53 class ASH_EXPORT OverviewWindowDragController {
54  public:
55   enum class DragBehavior {
56     // No drag has started.
57     kNoDrag,
58     // Drag has started, but it is undecided whether we want to drag to snap or
59     // drag to close yet.
60     kUndefined,
61     // On drag complete, the window will be snapped, if it meets requirements,
62     // or moved to another desk if dropped on one of the desks' mini_views. This
63     // mode is triggered if the the window is initially dragged horizontally
64     // more than vertically (more in X than Y), or if the window item in the
65     // overview grid was gesture long pressed.
66     kNormalDrag,
67     // On drag complete, the window will be closed, if it meets requirements.
68     // This mode is triggered when the window is initially dragged vertically
69     // more than horizontally (more in Y than in X).
70     kDragToClose,
71   };
72 
73   enum class DragResult {
74     // The drag ended without ever being disambiguated between a normal drag and
75     // drag-to-close.
76     kNeverDisambiguated,
77     // The drag was considered as a normal drag, and then the window was dropped
78     // back into overview, in the same grid or another one.
79     kDropIntoOverview,
80     // The drag resulted in snapping the window.
81     kSnap,
82     // The drag resulted in moving the window to another desk.
83     kDragToDesk,
84     // The drag resulted in closing the window.
85     kSuccessfulDragToClose,
86     // The drag was considered as drag-to-close, but did not result in closing
87     // the window.
88     kCanceledDragToClose,
89   };
90 
91   OverviewWindowDragController(OverviewSession* overview_session,
92                                OverviewItem* item,
93                                bool is_touch_dragging);
94   ~OverviewWindowDragController();
95 
96   void InitiateDrag(const gfx::PointF& location_in_screen);
97   void Drag(const gfx::PointF& location_in_screen);
98   DragResult CompleteDrag(const gfx::PointF& location_in_screen);
99   void StartNormalDragMode(const gfx::PointF& location_in_screen);
100   DragResult Fling(const gfx::PointF& location_in_screen,
101                    float velocity_x,
102                    float velocity_y);
103   void ActivateDraggedWindow();
104   void ResetGesture();
105 
106   // Resets |overview_session_| to nullptr. It's needed since we defer the
107   // deletion of OverviewWindowDragController in Overview destructor and
108   // we need to reset |overview_session_| to nullptr to avoid null pointer
109   // dereference.
110   void ResetOverviewSession();
111 
item()112   OverviewItem* item() { return item_; }
113 
current_drag_behavior()114   DragBehavior current_drag_behavior() { return current_drag_behavior_; }
115 
is_touch_dragging()116   bool is_touch_dragging() const { return is_touch_dragging_; }
117 
118  private:
119   enum NormalDragAction {
120     kToGrid = 0,
121     kToDesk = 1,
122     kToSnap = 2,
123     kNormalDragActionEnumSize = 3,
124   };
125   enum DragToCloseAction {
126     kSwipeToCloseSuccessful = 0,
127     kSwipeToCloseCanceled = 1,
128     kFlingToClose = 2,
129     kDragToCloseActionEnumSize = 3,
130   };
131 
132   void StartDragToCloseMode();
133 
134   // Methods to continue and complete the drag when the drag mode is
135   // kDragToClose.
136   void ContinueDragToClose(const gfx::PointF& location_in_screen);
137   DragResult CompleteDragToClose(const gfx::PointF& location_in_screen);
138 
139   // Methods to continue and complete the drag when the drag mode is
140   // kNormalDrag.
141   void ContinueNormalDrag(const gfx::PointF& location_in_screen);
142   DragResult CompleteNormalDrag(const gfx::PointF& location_in_screen);
143 
144   // Updates visuals for the user while dragging items around.
145   void UpdateDragIndicatorsAndOverviewGrid(
146       const gfx::PointF& location_in_screen);
147 
148   aura::Window* GetRootWindowBeingDraggedIn() const;
149 
150   SplitViewController::SnapPosition GetSnapPosition(
151       const gfx::PointF& location_in_screen) const;
152 
153   // Snaps and activates the window. Uses the divider spawn animation (see
154   // |SplitViewController::SnapWindow|). Sets |item_| to null because the
155   // overview item is destroyed.
156   void SnapWindow(SplitViewController* split_view_controller,
157                   SplitViewController::SnapPosition snap_position);
158 
159   // Returns the item's overview grid, or the grid in which the item is being
160   // dragged if the multi display overview and split view feature is enabled.
161   OverviewGrid* GetCurrentGrid() const;
162 
163   // Records the histogram Ash.Overview.WindowDrag.Workflow.
164   void RecordNormalDrag(NormalDragAction action,
165                         bool is_dragged_to_other_display) const;
166   void RecordDragToClose(DragToCloseAction action) const;
167 
168   OverviewSession* overview_session_;
169 
170   // The drag target window in the overview mode.
171   OverviewItem* item_ = nullptr;
172 
173   DragBehavior current_drag_behavior_ = DragBehavior::kNoDrag;
174 
175   // The location of the initial mouse/touch/gesture event in screen.
176   gfx::PointF initial_event_location_;
177 
178   // Stores the bounds of |item_| when a drag is started. Used to calculate the
179   // new bounds on a drag event.
180   gfx::PointF initial_centerpoint_;
181 
182   // The original size of the dragged item after we scale it up when we start
183   // dragging it. The item is restored to this size once it no longer intersects
184   // with the DesksBarView.
185   gfx::SizeF original_scaled_size_;
186 
187   // Track the per-overview-grid desks bar data used to perform the window
188   // sizing operations when it is moved towards or on the desks bar.
189   struct GridDesksBarData {
190     // The scaled-down size of the dragged item once the drag location is on the
191     // DesksBarView of the corresponding grid. We size the item down so that it
192     // fits inside the desks' preview view.
193     gfx::SizeF on_desks_bar_item_size;
194 
195     // Cached values related to dragging items while the desks bar is shown.
196     // |desks_bar_bounds| is the bounds of the desks bar in screen coordinates.
197     // |shrink_bounds| is a rectangle around the desks bar which the items
198     // starts shrinking when the event location is contained. The item will
199     // shrink until it is contained in |desks_bar_bounds|, at which it has
200     // reached its minimum size and will no longer shrink.
201     // |shrink_region_distance| is a vector contained the distance from the
202     // origin of |desks_bar_bounds| to the origin of |shrink_bounds|. It's
203     // used to determine the size of the dragged item when it's within
204     // |shrink_bounds|.
205     gfx::RectF desks_bar_bounds;
206     gfx::RectF shrink_bounds;
207     gfx::Vector2dF shrink_region_distance;
208   };
209   base::flat_map<OverviewGrid*, GridDesksBarData> per_grid_desks_bar_data_;
210 
211   const size_t display_count_;
212 
213   // Indicates touch dragging, as opposed to mouse dragging. The drag-to-close
214   // mode is only allowed when |is_touch_dragging_| is true.
215   const bool is_touch_dragging_;
216 
217   // True if SplitView is enabled.
218   const bool should_allow_split_view_;
219 
220   // True if the Virtual Desks bar is created and dragging to desks is enabled.
221   const bool virtual_desks_bar_enabled_;
222 
223   const bool are_multi_display_overview_and_splitview_enabled_;
224 
225   // The opacity of |item_| changes if we are in drag to close mode. Store the
226   // original opacity of |item_| and restore it to the item when we leave drag
227   // to close mode.
228   float original_opacity_ = 1.f;
229 
230   // Set to true once the bounds of |item_| change.
231   bool did_move_ = false;
232 
233   // Records the presentation time of window drag operation in overview mode.
234   std::unique_ptr<PresentationTimeRecorder> presentation_time_recorder_;
235 
236   SplitViewController::SnapPosition snap_position_ = SplitViewController::NONE;
237 
238   DISALLOW_COPY_AND_ASSIGN(OverviewWindowDragController);
239 };
240 
241 }  // namespace ash
242 
243 #endif  // ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
244