1 // Copyright 2018 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_MULTI_USER_MULTI_USER_WINDOW_MANAGER_IMPL_H_ 6 #define ASH_MULTI_USER_MULTI_USER_WINDOW_MANAGER_IMPL_H_ 7 8 #include <map> 9 #include <memory> 10 11 #include "ash/ash_export.h" 12 #include "ash/public/cpp/multi_user_window_manager.h" 13 #include "ash/public/cpp/session/session_observer.h" 14 #include "ash/public/cpp/tablet_mode_observer.h" 15 #include "base/containers/flat_map.h" 16 #include "base/macros.h" 17 #include "base/observer_list.h" 18 #include "base/time/time.h" 19 #include "components/account_id/account_id.h" 20 #include "ui/aura/window_observer.h" 21 #include "ui/wm/core/transient_window_observer.h" 22 23 namespace ash { 24 25 class MultiUserWindowManagerDelegate; 26 class UserSwitchAnimator; 27 28 // MultiUserWindowManager associates windows with users and ensures the 29 // appropriate set of windows are visible at the right time. 30 // MultiUserWindowManager must be explicitly told about the windows to manage. 31 // This is done by way of SetWindowOwner(). 32 // 33 // Each window may be associated with two accounts. The owning account (the 34 // account supplied to SetWindowOwner()), and an account the window is shown 35 // with when the account is active. Typically the 'shown' account and 'owning' 36 // account are the same, but the user may choose to show a window from an other 37 // account, in which case the 'shown' account changes. 38 // 39 // Note: 40 // - aura::Window::Hide() is currently hiding the window and all owned transient 41 // children. However aura::Window::Show() is only showing the window itself. 42 // To address that, all transient children (and their children) are remembered 43 // in |transient_window_to_visibility_| and monitored to keep track of the 44 // visibility changes from the owning user. This way the visibility can be 45 // changed back to its requested state upon showing by us - or when the window 46 // gets detached from its current owning parent. 47 class ASH_EXPORT MultiUserWindowManagerImpl 48 : public MultiUserWindowManager, 49 public SessionObserver, 50 public aura::WindowObserver, 51 public ::wm::TransientWindowObserver, 52 public TabletModeObserver { 53 public: 54 // The speed which should be used to perform animations. 55 enum AnimationSpeed { 56 ANIMATION_SPEED_NORMAL, // The normal animation speed. 57 ANIMATION_SPEED_FAST, // Unit test speed which test animations. 58 ANIMATION_SPEED_DISABLED // Unit tests which do not require animations. 59 }; 60 61 MultiUserWindowManagerImpl(MultiUserWindowManagerDelegate* delegate, 62 const AccountId& account_id); 63 ~MultiUserWindowManagerImpl() override; 64 65 static MultiUserWindowManagerImpl* Get(); 66 67 // Called when the active account change is complete. 68 void OnDidSwitchActiveAccount(); 69 70 // MultiUserWindowManager: 71 void SetWindowOwner(aura::Window* window, 72 const AccountId& account_id) override; 73 void ShowWindowForUser(aura::Window* window, 74 const AccountId& account_id) override; 75 const AccountId& GetWindowOwner(const aura::Window* window) const override; 76 bool AreWindowsSharedAmongUsers() const override; 77 std::set<AccountId> GetOwnersOfVisibleWindows() const override; 78 const AccountId& GetUserPresentingWindow( 79 const aura::Window* window) const override; 80 const AccountId& CurrentAccountId() const override; 81 void AddObserver(MultiUserWindowManagerObserver* observer) override; 82 void RemoveObserver(MultiUserWindowManagerObserver* observer) override; 83 84 // SessionObserver: 85 void OnActiveUserSessionChanged(const AccountId& account_id) override; 86 87 // WindowObserver overrides: 88 void OnWindowDestroyed(aura::Window* window) override; 89 void OnWindowVisibilityChanging(aura::Window* window, bool visible) override; 90 void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; 91 92 // TransientWindowObserver overrides: 93 void OnTransientChildAdded(aura::Window* window, 94 aura::Window* transient) override; 95 void OnTransientChildRemoved(aura::Window* window, 96 aura::Window* transient) override; 97 98 // TabletModeObserver: 99 void OnTabletModeStarted() override; 100 101 // Disable any animations for unit tests. 102 void SetAnimationSpeedForTest(AnimationSpeed speed); 103 104 // Returns true when a user switch animation is running. For unit tests. 105 bool IsAnimationRunningForTest(); 106 107 // Returns the current user for unit tests. 108 const AccountId& GetCurrentUserForTest() const; 109 110 private: 111 friend class MultiProfileSupportTest; 112 friend class UserSwitchAnimator; 113 114 class WindowEntry { 115 public: 116 explicit WindowEntry(const AccountId& account_id); 117 ~WindowEntry(); 118 119 // Returns the owner of this window. This cannot be changed. owner()120 const AccountId& owner() const { return owner_; } 121 122 // Returns the user for which this should be shown. show_for_user()123 const AccountId& show_for_user() const { return show_for_user_; } 124 125 // Returns if the window should be shown for the "show user" or not. show()126 bool show() const { return show_; } 127 128 // Set the user which will display the window on the owned desktop. If 129 // an empty user id gets passed the owner will be used. set_show_for_user(const AccountId & account_id)130 void set_show_for_user(const AccountId& account_id) { 131 show_for_user_ = account_id.is_valid() ? account_id : owner_; 132 } 133 134 // Sets if the window gets shown for the active user or not. set_show(bool show)135 void set_show(bool show) { show_ = show; } 136 137 private: 138 // The user id of the owner of this window. 139 const AccountId owner_; 140 141 // The user id of the user on which desktop the window gets shown. 142 AccountId show_for_user_; 143 144 // True if the window should be visible for the user which shows the window. 145 bool show_ = true; 146 147 DISALLOW_COPY_AND_ASSIGN(WindowEntry); 148 }; 149 150 using TransientWindowToVisibility = base::flat_map<aura::Window*, bool>; 151 152 using WindowToEntryMap = 153 std::map<aura::Window*, std::unique_ptr<WindowEntry>>; 154 155 // Returns true if the 'shown' owner of |window| is |account_id|. 156 bool IsWindowOnDesktopOfUser(aura::Window* window, 157 const AccountId& account_id) const; 158 159 // Returns the 'shown' owner. 160 const AccountId& GetUserPresentingWindow(aura::Window* window) const; 161 162 // Show a window for a user without switching the user. 163 // Returns true when the window moved to a new desktop. 164 bool ShowWindowForUserIntern(aura::Window* window, 165 const AccountId& account_id); 166 167 // Show / hide the given window. Note: By not doing this within the functions, 168 // this allows to either switching to different ways to show/hide and / or to 169 // distinguish state changes performed by this class vs. state changes 170 // performed by the others. Note furthermore that system modal dialogs will 171 // not get hidden. We will switch instead to the owners desktop. 172 // The |animation_time| is the time the animation should take, an empty value 173 // switches instantly. 174 void SetWindowVisibility(aura::Window* window, 175 bool visible, 176 base::TimeDelta animation_time = base::TimeDelta()); 177 window_to_entry()178 const WindowToEntryMap& window_to_entry() { return window_to_entry_; } 179 180 // Show the window and its transient children. However - if a transient child 181 // was turned invisible by some other operation, it will stay invisible. 182 // |animation_time| is the amount of time to animate. 183 void ShowWithTransientChildrenRecursive(aura::Window* window, 184 base::TimeDelta animation_time); 185 186 // Find the first owned window in the chain. 187 // Returns NULL when the window itself is owned. 188 aura::Window* GetOwningWindowInTransientChain(aura::Window* window) const; 189 190 // A |window| and its children were attached as transient children to an 191 // |owning_parent| and need to be registered. Note that the |owning_parent| 192 // itself will not be registered, but its children will. 193 void AddTransientOwnerRecursive(aura::Window* window, 194 aura::Window* owning_parent); 195 196 // A window and its children were removed from its parent and can be 197 // unregistered. 198 void RemoveTransientOwnerRecursive(aura::Window* window); 199 200 // Animate a |window| to be |visible| over a time of |animation_time|. 201 void SetWindowVisible(aura::Window* window, 202 bool visible, 203 base::TimeDelta aimation_time); 204 205 // Returns the time for an animation. 206 base::TimeDelta GetAdjustedAnimationTime(base::TimeDelta default_time) const; 207 208 MultiUserWindowManagerDelegate* delegate_; 209 210 // A lookup to see to which user the given window belongs to, where and if it 211 // should get shown. 212 WindowToEntryMap window_to_entry_; 213 214 // A map which remembers for owned transient windows their own visibility. 215 TransientWindowToVisibility transient_window_to_visibility_; 216 217 // The currently selected active user. It is used to find the proper 218 // visibility state in various cases. The state is stored here instead of 219 // being read from the user manager to be in sync while a switch occurs. 220 AccountId current_account_id_; 221 222 // Suppress changes to the visibility flag while we are changing it ourselves. 223 bool suppress_visibility_changes_ = false; 224 225 // The speed which is used to perform any animations. 226 AnimationSpeed animation_speed_ = ANIMATION_SPEED_NORMAL; 227 228 // The animation between users. 229 std::unique_ptr<UserSwitchAnimator> animation_; 230 231 base::ObserverList<MultiUserWindowManagerObserver>::Unchecked observers_; 232 233 DISALLOW_COPY_AND_ASSIGN(MultiUserWindowManagerImpl); 234 }; 235 236 } // namespace ash 237 238 #endif // ASH_MULTI_USER_MULTI_USER_WINDOW_MANAGER_IMPL_H_ 239