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