1 // Copyright 2013 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_ITEM_H_
6 #define ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_
7 
8 #include <memory>
9 
10 #include "ash/ash_export.h"
11 #include "ash/wm/overview/overview_session.h"
12 #include "ash/wm/overview/scoped_overview_transform_window.h"
13 #include "ash/wm/window_state_observer.h"
14 #include "base/macros.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/optional.h"
17 #include "ui/aura/window.h"
18 #include "ui/aura/window_observer.h"
19 #include "ui/gfx/geometry/rect.h"
20 #include "ui/gfx/geometry/rect_f.h"
21 #include "ui/views/controls/button/button.h"
22 
23 namespace ui {
24 class Shadow;
25 }  // namespace ui
26 
27 namespace views {
28 class Widget;
29 }  // namespace views
30 
31 namespace ash {
32 class DragWindowController;
33 class OverviewGrid;
34 class OverviewItemView;
35 class RoundedLabelWidget;
36 
37 // This class represents an item in overview mode.
38 class ASH_EXPORT OverviewItem : public aura::WindowObserver,
39                                 public WindowStateObserver {
40  public:
41   OverviewItem(aura::Window* window,
42                OverviewSession* overview,
43                OverviewGrid* overview_grid);
44   ~OverviewItem() override;
45 
46   aura::Window* GetWindow();
47 
48   // Returns true if |target| is contained in this OverviewItem.
49   bool Contains(const aura::Window* target) const;
50 
51   // This called when the window is dragged and dropped on the mini view of
52   // another desk, which prepares this item for being removed from the grid, and
53   // the window to restore its transform.
54   void OnMovingWindowToAnotherDesk();
55 
56   // Restores and animates the managed window to its non overview mode state.
57   // If |reset_transform| equals false, the window's transform will not be
58   // reset to identity transform when exiting overview mode. It's needed when
59   // dragging an Arc app window in overview mode to put it in split screen. In
60   // this case the restore of its transform needs to be deferred until the Arc
61   // app window is snapped successfully, otherwise the animation will look very
62   // ugly (the Arc app window enlarges itself to maximized window bounds and
63   // then shrinks to its snapped window bounds). Note if the window's transform
64   // is not reset here, it must be reset by someone else at some point.
65   void RestoreWindow(bool reset_transform);
66 
67   // Ensures that a possibly minimized window becomes visible after restore.
68   void EnsureVisible();
69 
70   // Restores stacking of window captions above the windows, then fades out.
71   void Shutdown();
72 
73   // Dispatched before beginning window overview. This will do any necessary
74   // one time actions such as restoring minimized windows.
75   void PrepareForOverview();
76 
77   // Calculates and returns an optimal scale ratio. With MD this is only
78   // taking into account |size.height()| as the width can vary. Without MD this
79   // returns the scale that allows the item to fully fit within |size|.
80   float GetItemScale(const gfx::Size& size);
81 
82   // Returns the union of the original target bounds of all transformed windows
83   // managed by |this| item, i.e. all regular (normal or panel transient
84   // descendants of the window returned by GetWindow()).
85   gfx::RectF GetTargetBoundsInScreen() const;
86 
87   // Returns the transformed bound of |transform_window_|.
88   gfx::RectF GetTransformedBounds() const;
89 
90   // Sets the bounds of this overview item to |target_bounds| in the
91   // |root_window_| root window. The bounds change will be animated as specified
92   // by |animation_type|.
93   void SetBounds(const gfx::RectF& target_bounds,
94                  OverviewAnimationType animation_type);
95 
96   // Sends an accessibility event indicating that this window became selected
97   // so that it is highlighted and announced.
98   void SendAccessibleSelectionEvent();
99 
100   // Slides the item up or down and then closes the associated window. Used by
101   // overview swipe to close.
102   void AnimateAndCloseWindow(bool up);
103 
104   // Closes |transform_window_|.
105   void CloseWindow();
106 
107   // Shows the cannot snap warning if currently in splitview, and the associated
108   // window cannot be snapped.
109   void UpdateCannotSnapWarningVisibility();
110 
111   // Hides the cannot snap warning (if it was showing) until the next call to
112   // |UpdateCannotSnapWarningVisibility|.
113   void HideCannotSnapWarning();
114 
115   // Called when a OverviewItem on any grid is dragged. Hides the close button
116   // when a drag is started, and reshows it when a drag is finished.
117   // Additionally hides the title and window icon if |item| is this.
118   void OnSelectorItemDragStarted(OverviewItem* item);
119   void OnSelectorItemDragEnded(bool snap);
120 
121   // Shows/Hides window item during window dragging. Used when swiping up a
122   // window from shelf.
123   void SetVisibleDuringWindowDragging(bool visible, bool animate);
124 
125   OverviewGridWindowFillMode GetWindowDimensionsType() const;
126 
127   // Recalculates the window dimensions type of |transform_window_|. Called when
128   // |window_|'s bounds change.
129   void UpdateWindowDimensionsType();
130 
131   // TODO(minch): Do not actually scale up the item to get the bounds.
132   // http://crbug.com/876567.
133   // Returns the bounds of the selected item, which will be scaled up a little
134   // bit and header view will be hidden after being selected. Note, the item
135   // will be restored back after scaled up.
136   gfx::Rect GetBoundsOfSelectedItem();
137 
138   // Increases the bounds of the dragged item.
139   void ScaleUpSelectedItem(OverviewAnimationType animation_type);
140 
141   // If the window item represents a minimized window, update its content view.
142   void UpdateItemContentViewForMinimizedWindow();
143 
144   // Checks if this item is currently being dragged.
145   bool IsDragItem();
146 
147   // Inserts the window back to its original stacking order so that the order of
148   // windows is the same as when entering overview.
149   void Restack();
150 
151   // Updates |phantoms_for_dragging_|. If |phantoms_for_dragging_| is null, then
152   // a new object is created for it.
153   void UpdatePhantomsForDragging(bool is_touch_dragging);
154 
155   void DestroyPhantomsForDragging();
156 
157   // Sets the bounds of the window shadow. If |bounds_in_screen| is nullopt,
158   // the shadow is hidden.
159   void SetShadowBounds(base::Optional<gfx::RectF> bounds_in_screen);
160 
161   // Updates the rounded corners and shadow on this overview window item.
162   void UpdateRoundedCornersAndShadow();
163 
164   // Called when the starting animation is completed, or called immediately
165   // if there was no starting animation.
166   void OnStartingAnimationComplete();
167 
168   // Stops the current animation of |item_widget_|.
169   void StopWidgetAnimation();
170 
171   // Changes the opacity of all the windows the item owns.
172   void SetOpacity(float opacity);
173   float GetOpacity();
174 
175   OverviewAnimationType GetExitOverviewAnimationType();
176   OverviewAnimationType GetExitTransformAnimationType();
177 
178   // If kNewOverviewLayout is on, use this function for handling events.
179   void HandleGestureEventForTabletModeLayout(ui::GestureEvent* event);
180 
181   // Handles events forwarded from |overview_item_view_|.
182   void HandleMouseEvent(const ui::MouseEvent& event);
183   void HandleGestureEvent(ui::GestureEvent* event);
184   void OnHighlightedViewActivated();
185   void OnHighlightedViewClosed();
186 
187   // aura::WindowObserver:
188   void OnWindowPropertyChanged(aura::Window* window,
189                                const void* key,
190                                intptr_t old) override;
191   void OnWindowBoundsChanged(aura::Window* window,
192                              const gfx::Rect& old_bounds,
193                              const gfx::Rect& new_bounds,
194                              ui::PropertyChangeReason reason) override;
195   void OnWindowDestroying(aura::Window* window) override;
196 
197   // WindowStateObserver:
198   void OnPreWindowStateTypeChange(WindowState* window_state,
199                                   chromeos::WindowStateType old_type) override;
200   void OnPostWindowStateTypeChange(WindowState* window_state,
201                                    chromeos::WindowStateType old_type) override;
202 
203   // Returns the root window on which this item is shown.
root_window()204   aura::Window* root_window() { return root_window_; }
205 
target_bounds()206   const gfx::RectF& target_bounds() const { return target_bounds_; }
207 
item_widget()208   views::Widget* item_widget() { return item_widget_.get(); }
209 
overview_item_view()210   OverviewItemView* overview_item_view() { return overview_item_view_; }
211 
overview_grid()212   OverviewGrid* overview_grid() { return overview_grid_; }
213 
is_moving_to_another_desk()214   bool is_moving_to_another_desk() const { return is_moving_to_another_desk_; }
215 
set_should_use_spawn_animation(bool value)216   void set_should_use_spawn_animation(bool value) {
217     should_use_spawn_animation_ = value;
218   }
should_use_spawn_animation()219   bool should_use_spawn_animation() const {
220     return should_use_spawn_animation_;
221   }
222 
set_should_animate_when_entering(bool should_animate)223   void set_should_animate_when_entering(bool should_animate) {
224     should_animate_when_entering_ = should_animate;
225   }
should_animate_when_entering()226   bool should_animate_when_entering() const {
227     return should_animate_when_entering_;
228   }
229 
set_should_animate_when_exiting(bool should_animate)230   void set_should_animate_when_exiting(bool should_animate) {
231     should_animate_when_exiting_ = should_animate;
232   }
should_animate_when_exiting()233   bool should_animate_when_exiting() const {
234     return should_animate_when_exiting_;
235   }
236 
set_should_restack_on_animation_end(bool val)237   void set_should_restack_on_animation_end(bool val) {
238     should_restack_on_animation_end_ = val;
239   }
240 
set_animating_to_close(bool val)241   void set_animating_to_close(bool val) { animating_to_close_ = val; }
animating_to_close()242   bool animating_to_close() const { return animating_to_close_; }
243 
set_disable_mask(bool disable)244   void set_disable_mask(bool disable) { disable_mask_ = disable; }
245 
set_unclipped_size(base::Optional<gfx::Size> unclipped_size)246   void set_unclipped_size(base::Optional<gfx::Size> unclipped_size) {
247     unclipped_size_ = unclipped_size;
248   }
249 
250   gfx::Rect GetShadowBoundsForTesting();
cannot_snap_widget_for_testing()251   RoundedLabelWidget* cannot_snap_widget_for_testing() {
252     return cannot_snap_widget_.get();
253   }
set_target_bounds_for_testing(const gfx::RectF & target_bounds)254   void set_target_bounds_for_testing(const gfx::RectF& target_bounds) {
255     target_bounds_ = target_bounds;
256   }
257 
258  private:
259   friend class OverviewSessionTest;
260   FRIEND_TEST_ALL_PREFIXES(SplitViewOverviewSessionTest, Clipping);
261 
262   // Returns the target bounds of |window_|. Same as |target_bounds_|, with some
263   // insets.
264   gfx::RectF GetWindowTargetBoundsWithInsets() const;
265 
266   // The shadow should match the size of the transformed window or preview
267   // window if unclipped.
268   gfx::RectF GetUnclippedShadowBounds() const;
269 
270   // Functions to be called back when their associated animations complete.
271   void OnWindowCloseAnimationCompleted();
272   void OnItemSpawnedAnimationCompleted();
273   void OnItemBoundsAnimationStarted();
274   void OnItemBoundsAnimationEnded();
275 
276   // Performs the spawn-item-in-overview animation (which is a fade-in plus
277   // scale-up animation), on the given |window|. |target_transform| is the final
278   // transform that should be applied to |window| at the end of the animation.
279   // |window| is either the real window associated with this item (from
280   // GetWindow()), or the `item_widget_->GetNativeWindow()` if the associated
281   // window is minimized.
282   void PerformItemSpawnedAnimation(aura::Window* window,
283                                    const gfx::Transform& target_transform);
284 
285   // Sets the bounds of this overview item to |target_bounds| in |root_window_|.
286   // The bounds change will be animated as specified by |animation_type|.
287   // |is_first_update| is true when we set this item's bounds for the first
288   // time.
289   void SetItemBounds(const gfx::RectF& target_bounds,
290                      OverviewAnimationType animation_type,
291                      bool is_first_update);
292 
293   // Creates |item_widget_|, which holds |overview_item_view_|.
294   void CreateItemWidget();
295 
296   // Updates the |item_widget|'s bounds. Any change in bounds will be animated
297   // from the current bounds to the new bounds as per the |animation_type|.
298   void UpdateHeaderLayout(OverviewAnimationType animation_type);
299 
300   // Animates opacity of the |transform_window_| and its caption to |opacity|
301   // using |animation_type|.
302   void AnimateOpacity(float opacity, OverviewAnimationType animation_type);
303 
304   // Called before dragging. Scales up the window a little bit to indicate its
305   // selection and stacks the window at the top of the Z order in order to keep
306   // it visible while dragging around.
307   void StartDrag();
308 
309   void CloseButtonPressed();
310 
311   // TODO(sammiequon): Current events go from OverviewItemView to
312   // OverviewItem to OverviewSession to OverviewWindowDragController. We may be
313   // able to shorten this pipeline.
314   void HandlePressEvent(const gfx::PointF& location_in_screen,
315                         bool from_touch_gesture);
316   void HandleReleaseEvent(const gfx::PointF& location_in_screen);
317   void HandleDragEvent(const gfx::PointF& location_in_screen);
318   void HandleLongPressEvent(const gfx::PointF& location_in_screen);
319   void HandleFlingStartEvent(const gfx::PointF& location_in_screen,
320                              float velocity_x,
321                              float velocity_y);
322   void HandleTapEvent();
323   void HandleGestureEndEvent();
324 
325   // Returns the list of windows that we want to slide up or down when swiping
326   // on the shelf in tablet mode.
327   aura::Window::Windows GetWindowsForHomeGesture();
328 
329   // The root window this item is being displayed on.
330   aura::Window* root_window_;
331 
332   // The contained Window's wrapper.
333   ScopedOverviewTransformWindow transform_window_;
334 
335   // The target bounds this overview item is fit within. When in splitview,
336   // |item_widget_| is fit within these bounds, but the window itself is
337   // transformed to |unclipped_size_|, and then clipped.
338   gfx::RectF target_bounds_;
339 
340   // True if running SetItemBounds. This prevents recursive calls resulting from
341   // the bounds update when calling ::wm::RecreateWindowLayers to copy
342   // a window layer for display on another monitor.
343   bool in_bounds_update_ = false;
344 
345   // A widget stacked under the |transform_window_|. The widget has
346   // |overview_item_view_| as its contents view. The widget is backed by a
347   // NOT_DRAWN layer since most of its surface is transparent.
348   std::unique_ptr<views::Widget> item_widget_;
349 
350   // The view associated with |item_widget_|. Contains a title, close button and
351   // maybe a backdrop. Forwards certain events to |this|.
352   OverviewItemView* overview_item_view_ = nullptr;
353 
354   // A widget with text that may show up on top of |transform_window_| to notify
355   // users this window cannot be snapped.
356   std::unique_ptr<RoundedLabelWidget> cannot_snap_widget_;
357 
358   // Responsible for phantoms that look like the window on all displays during
359   // dragging.
360   std::unique_ptr<DragWindowController> phantoms_for_dragging_;
361 
362   // Pointer to the Overview that owns the OverviewGrid containing |this|.
363   // Guaranteed to be non-null for the lifetime of |this|.
364   OverviewSession* overview_session_;
365 
366   // Pointer to the OverviewGrid that contains |this|. Guaranteed to be non-null
367   // for the lifetime of |this|.
368   OverviewGrid* overview_grid_;
369 
370   // True when the item is dragged and dropped on another desk's mini view. This
371   // causes it to restore its transform immediately without any animations,
372   // since it is moving to an inactive desk, and therefore won't be visible.
373   bool is_moving_to_another_desk_ = false;
374 
375   // True if this item should be added to an active overview session using the
376   // spawn animation on its first update. This implies an animation type of
377   // OVERVIEW_ANIMATION_SPAWN_ITEM_IN_OVERVIEW. This value will be reset to
378   // false once the spawn animation is performed.
379   bool should_use_spawn_animation_ = false;
380 
381   // True if the contained window should animate during the entering animation.
382   bool should_animate_when_entering_ = true;
383 
384   // True if the contained window should animate during the exiting animation.
385   bool should_animate_when_exiting_ = true;
386 
387   // True if after an animation, we need to reorder the stacking order of the
388   // widgets.
389   bool should_restack_on_animation_end_ = false;
390 
391   // True if the windows are still alive so they can have a closing animation.
392   // These windows should not be used in calculations for
393   // OverviewGrid::PositionWindows.
394   bool animating_to_close_ = false;
395 
396   // True if this overview item is currently being dragged around.
397   bool is_being_dragged_ = false;
398 
399   // True to always disable mask regardless of the state.
400   bool disable_mask_ = false;
401 
402   bool prepared_for_overview_ = false;
403 
404   // This has a value when there is a snapped window, or a window about to be
405   // snapped (triggering a splitview preview area). This will be set when items
406   // are positioned in OverviewGrid. The bounds delivered in |SetBounds| are the
407   // true bounds of this item, but we want to maintain the aspect ratio of the
408   // window, who's bounds are not set to split view size. So in |SetItemBounds|,
409   // we transform the window not to |target_bounds_| but to this value, and then
410   // apply clipping on the window to |target_bounds_|.
411   base::Optional<gfx::Size> unclipped_size_ = base::nullopt;
412 
413   // The shadow around the overview window. Shadows the original window, not
414   // |item_widget_|. Done here instead of on the original window because of the
415   // rounded edges mask applied on entering overview window.
416   std::unique_ptr<ui::Shadow> shadow_;
417 
418   base::WeakPtrFactory<OverviewItem> weak_ptr_factory_{this};
419 
420   DISALLOW_COPY_AND_ASSIGN(OverviewItem);
421 };
422 
423 }  // namespace ash
424 
425 #endif  // ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_
426