1 // Copyright 2019 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_DESKS_DESKS_CONTROLLER_H_
6 #define ASH_WM_DESKS_DESKS_CONTROLLER_H_
7 
8 #include <memory>
9 #include <queue>
10 #include <vector>
11 
12 #include "ash/ash_export.h"
13 #include "ash/public/cpp/autotest_desks_api.h"
14 #include "ash/public/cpp/desks_helper.h"
15 #include "ash/public/cpp/session/session_observer.h"
16 #include "ash/wm/desks/desks_histogram_enums.h"
17 #include "ash/wm/desks/root_window_desk_switch_animator.h"
18 #include "base/containers/flat_map.h"
19 #include "base/macros.h"
20 #include "base/observer_list.h"
21 #include "components/account_id/account_id.h"
22 #include "ui/wm/public/activation_change_observer.h"
23 
24 namespace aura {
25 class Window;
26 }  // namespace aura
27 
28 namespace ash {
29 
30 class Desk;
31 class DeskAnimationBase;
32 
33 // Defines a controller for creating, destroying and managing virtual desks and
34 // their windows.
35 class ASH_EXPORT DesksController : public DesksHelper,
36                                    public wm::ActivationChangeObserver,
37                                    public SessionObserver {
38  public:
39   class Observer {
40    public:
41     // Called when |desk| has been created and added to
42     // `DesksController::desks_`.
43     virtual void OnDeskAdded(const Desk* desk) = 0;
44 
45     // Called when |desk| has been removed from `DesksController::desks_`.
46     // However |desk| is kept alive temporarily and will be destroyed after all
47     // observers have been notified with this.
48     virtual void OnDeskRemoved(const Desk* desk) = 0;
49 
50     // Called when the |activated| desk gains activation from the |deactivated|
51     // desk.
52     virtual void OnDeskActivationChanged(const Desk* activated,
53                                          const Desk* deactivated) = 0;
54 
55     // Called when the desk switch animations is launching.
56     virtual void OnDeskSwitchAnimationLaunching() = 0;
57 
58     // Called when the desk switch animations on all root windows finish.
59     virtual void OnDeskSwitchAnimationFinished() = 0;
60 
61    protected:
62     virtual ~Observer() = default;
63   };
64 
65   DesksController();
66   ~DesksController() override;
67 
68   // Convenience method for returning the DesksController instance. The actual
69   // instance is created and owned by Shell.
70   static DesksController* Get();
71 
desks()72   const std::vector<std::unique_ptr<Desk>>& desks() const { return desks_; }
73 
active_desk()74   const Desk* active_desk() const { return active_desk_; }
75 
animation()76   DeskAnimationBase* animation() const { return animation_.get(); }
77 
78   // Returns the current |active_desk()| or the soon-to-be active desk if a desk
79   // switch animation is in progress.
80   const Desk* GetTargetActiveDesk() const;
81 
82   // Restores the primary user's activate desk at active_desk_index.
83   void RestorePrimaryUserActiveDeskIndex(int active_desk_index);
84 
85   // Destroys any pending animations in preparation for shutdown.
86   void Shutdown();
87 
88   void AddObserver(Observer* observer);
89   void RemoveObserver(Observer* observer);
90 
91   // Returns true if desks are being modified due to desk creation, removal, or
92   // activation. It also returns true while the desk switch animation is in
93   // progress.
94   bool AreDesksBeingModified() const;
95 
96   // Returns true if we haven't reached the maximum allowed number of desks.
97   bool CanCreateDesks() const;
98 
99   // Returns true as long as there are two or more desks. It is required that
100   // there is at least one single desk at any time.
101   bool CanRemoveDesks() const;
102 
103   // Returns the next / previous desks to the target / currently active desk.
104   // Returns nullptr if the active desk is the first on the left or the last on
105   // the right, and previous and next desks are requested respectively.
106   Desk* GetNextDesk(bool use_target_active_desk = true) const;
107   Desk* GetPreviousDesk(bool use_target_active_desk = true) const;
108 
109   // Creates a new desk. CanCreateDesks() must be checked before calling this.
110   void NewDesk(DesksCreationRemovalSource source);
111 
112   // Removes and deletes the given |desk|. |desk| must already exist, and
113   // CanRemoveDesks() must be checked before this.
114   // This will trigger the `DeskRemovalAnimation` if the active desk is being
115   // removed outside of overview.
116   void RemoveDesk(const Desk* desk, DesksCreationRemovalSource source);
117 
118   // Performs the desk switch animation on all root windows to activate the
119   // given |desk| and to deactivate the currently active one. |desk| has to be
120   // an existing desk. The active window on the currently active desk will be
121   // deactivated, and the most-recently used window from the newly-activated
122   // desk will be activated.
123   // This will trigger the `DeskActivationAnimation`.
124   void ActivateDesk(const Desk* desk, DesksSwitchSource source);
125 
126   // Activates the desk to the left or right of the current desk, if it exists.
127   // Performs a hit the wall animation if there is no desk to activate. Returns
128   // false if there is already a desk animation active. This function will then
129   // do nothing, no desk switch or hit the wall animation.
130   bool ActivateAdjacentDesk(bool going_left, DesksSwitchSource source);
131 
132   // Functions used by WmGestureHandler to modify the current touchpad desk
133   // animation, if it exists. StartSwipeAnimation starts a new animation to
134   // an adjacent desk, or replaces an existing swipe animation. It returns
135   // true if either of those were successful, false otherwise.
136   bool StartSwipeAnimation(bool move_left);
137   void UpdateSwipeAnimation(float scroll_delta_x);
138   void EndSwipeAnimation();
139 
140   // Moves |window| (which must belong to the currently active desk) to
141   // |target_desk| (which must be a different desk).
142   // |target_root| is provided if |window| is desired to be moved to another
143   // desk on another display, otherwise, you can just provide
144   // |window->GetRootWindow()| if the window should stay on the same display.
145   // If |window| is minimized, it will be unminimized after it's moved to
146   // |target_desk|.
147   // Returns true on success, false otherwise (e.g. if |window| doesn't belong
148   // to the active desk).
149   bool MoveWindowFromActiveDeskTo(aura::Window* window,
150                                   Desk* target_desk,
151                                   aura::Window* target_root,
152                                   DesksMoveWindowFromActiveDeskSource source);
153 
154   // Reverts the name of the given |desk| to the default value (i.e. "Desk 1",
155   // "Desk 2", ... etc.) according to its position in the |desks_| list, as if
156   // it was never modified by users.
157   void RevertDeskNameToDefault(Desk* desk);
158 
159   // Restores the desk at |index| to the given |name|. This is only for user-
160   // modified desk names, and hence |name| should never be empty since users are
161   // not allowed to set empty names.
162   void RestoreNameOfDeskAtIndex(base::string16 name, size_t index);
163 
164   // Called explicitly by the RootWindowController when a root window has been
165   // added or about to be removed in order to update all the available desks.
166   void OnRootWindowAdded(aura::Window* root_window);
167   void OnRootWindowClosing(aura::Window* root_window);
168 
169   int GetDeskIndex(const Desk* desk) const;
170 
171   // DesksHelper:
172   bool BelongsToActiveDesk(aura::Window* window) override;
173 
174   // ::wm::ActivationChangeObserver:
175   void OnWindowActivating(ActivationReason reason,
176                           aura::Window* gaining_active,
177                           aura::Window* losing_active) override;
178   void OnWindowActivated(ActivationReason reason,
179                          aura::Window* gained_active,
180                          aura::Window* lost_active) override;
181 
182   // SessionObserver:
183   void OnActiveUserSessionChanged(const AccountId& account_id) override;
184   void OnFirstSessionStarted() override;
185 
186  private:
187   class DeskTraversalsMetricsHelper;
188   friend class DeskAnimationBase;
189   friend class DeskActivationAnimation;
190   friend class DeskRemovalAnimation;
191 
192   void OnAnimationFinished(DeskAnimationBase* animation);
193 
194   bool HasDesk(const Desk* desk) const;
195 
196   // Activates the given |desk| and deactivates the currently active one. |desk|
197   // has to be an existing desk. If |update_window_activation| is true,
198   // the active desk on the deactivated desk will be deactivated, and the most-
199   // recently used window on the newly-activated desk will be deactivated. This
200   // parameter is almost always true except when the active desk is being
201   // removed while in overview mode. In that case, windows from the active desk
202   // will move to another desk and remain in the overview grid, and no
203   // activation or deactivation should be done in order to keep overview mode
204   // active.
205   void ActivateDeskInternal(const Desk* desk, bool update_window_activation);
206 
207   // Removes `desk` without animation.
208   void RemoveDeskInternal(const Desk* desk, DesksCreationRemovalSource source);
209 
210   // Returns the desk to which |window| belongs or nullptr if it doesn't belong
211   // to any desk.
212   const Desk* FindDeskOfWindow(aura::Window* window) const;
213 
214   // Reports the number of windows per each available desk. This called when a
215   // desk switch occurs.
216   void ReportNumberOfWindowsPerDeskHistogram() const;
217 
218   void ReportDesksCountHistogram() const;
219 
220   // Updates the default names (e.g. "Desk 1", "Desk 2", ... etc.) given to the
221   // desks. This is called when desks are added or removed to update the names
222   // based on the desks order.
223   void UpdateDesksDefaultNames();
224 
225   std::vector<std::unique_ptr<Desk>> desks_;
226 
227   Desk* active_desk_ = nullptr;
228 
229   // The account ID of the current active user.
230   AccountId current_account_id_;
231 
232   // Stores the per-user last active desk index.
233   base::flat_map<AccountId, int> user_to_active_desk_index_;
234 
235   // True when desks addition, removal, or activation change are in progress.
236   // This can be checked when overview mode is active to avoid exiting overview
237   // mode as a result of desks modifications.
238   bool are_desks_being_modified_ = false;
239 
240   // Not null if there is an on-going desks animation.
241   std::unique_ptr<DeskAnimationBase> animation_;
242 
243   // A free list of desk container IDs to be used for newly-created desks. New
244   // desks pops from this queue and removed desks's associated container IDs are
245   // re-pushed on this queue.
246   std::queue<int> available_container_ids_;
247 
248   // True when the enhanced desk animations feature is enabled.
249   const bool is_enhanced_desk_animations_;
250 
251   // Responsible for tracking and writing number of desk traversals one has
252   // done within a span of X seconds.
253   std::unique_ptr<DeskTraversalsMetricsHelper> metrics_helper_;
254 
255   base::ObserverList<Observer>::Unchecked observers_;
256 
257   DISALLOW_COPY_AND_ASSIGN(DesksController);
258 };
259 
260 }  // namespace ash
261 
262 #endif  // ASH_WM_DESKS_DESKS_CONTROLLER_H_
263