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