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.
5 #include "chrome/browser/ui/ash/multi_user_window_manager.h"
8 #include "ash/test/ash_test_base.h"
9 #include "ash/test/test_shell_delegate.h"
10 #include "ash/wm/window_state.h"
11 #include "base/command_line.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "ui/aura/client/activation_client.h"
17 #include "ui/aura/client/aura_constants.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/base/ui_base_types.h"
24 // A test class for preparing the chrome::MultiUserWindowManager. It creates
25 // various windows and instantiates the chrome::MultiUserWindowManager.
26 class MultiUserWindowManagerTest : public AshTestBase {
28 MultiUserWindowManagerTest() : multi_user_window_manager_(NULL) {}
30 virtual void SetUp() OVERRIDE;
31 virtual void TearDown() OVERRIDE;
34 // Set up the test environment for this many windows.
35 void SetUpForThisManyWindows(int windows);
37 // Return the window with the given index.
38 aura::Window* window(size_t index) {
39 DCHECK(index < window_.size());
40 return window_[index];
43 // The accessor to the MultiWindowManager.
44 chrome::MultiUserWindowManager* multi_user_window_manager() {
45 return multi_user_window_manager_;
48 // Returns a list of all open windows in the following form:
49 // "<H(idden)/S(hown)>[<Owner>[,<shownForUser>]], .."
50 // Like: "S[B], .." would mean that window#0 is shown and belongs to user B.
51 // or "S[B,A], .." would mean that window#0 is shown, belongs to B but is
53 std::string GetStatus();
56 // These get created for each session.
57 std::vector<aura::Window*> window_;
59 // The instance of the MultiUserWindowManager.
60 chrome::MultiUserWindowManager* multi_user_window_manager_;
62 DISALLOW_COPY_AND_ASSIGN(MultiUserWindowManagerTest);
65 void MultiUserWindowManagerTest::SetUp() {
66 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMultiProfiles);
70 void MultiUserWindowManagerTest::SetUpForThisManyWindows(int windows) {
71 DCHECK(!window_.size());
72 for (int i = 0; i < windows; i++) {
73 window_.push_back(CreateTestWindowInShellWithId(i));
76 multi_user_window_manager_ =
77 chrome::MultiUserWindowManager::CreateInstanceInternal("A");
78 EXPECT_TRUE(multi_user_window_manager_);
81 void MultiUserWindowManagerTest::TearDown() {
82 // Since the AuraTestBase is needed to create our assets, we have to
83 // also delete them before we tear it down.
84 while (!window_.empty()) {
85 delete *(window_.begin());
86 window_.erase(window_.begin());
89 AshTestBase::TearDown();
90 chrome::MultiUserWindowManager::DeleteInstance();
93 std::string MultiUserWindowManagerTest::GetStatus() {
95 for (size_t i = 0; i < window_.size(); i++) {
98 s += window(i)->IsVisible() ? "S[" : "H[";
99 const std::string& owner =
100 multi_user_window_manager_->GetWindowOwner(window(i));
102 const std::string& presenter =
103 multi_user_window_manager_->GetUserPresentingWindow(window(i));
104 if (!owner.empty() && owner != presenter) {
113 // Testing basic assumptions like default state and existence of manager.
114 TEST_F(MultiUserWindowManagerTest, BasicTests) {
115 SetUpForThisManyWindows(3);
116 // Check the basic assumptions: All windows are visible and there is no owner.
117 EXPECT_EQ("S[], S[], S[]", GetStatus());
118 EXPECT_TRUE(multi_user_window_manager());
119 EXPECT_EQ(multi_user_window_manager(),
120 chrome::MultiUserWindowManager::GetInstance());
121 EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
123 // The owner of an unowned window should be empty and it should be shown on
125 EXPECT_EQ("", multi_user_window_manager()->GetWindowOwner(window(0)));
127 multi_user_window_manager()->GetUserPresentingWindow(window(0)));
129 multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
131 multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
133 // Set the owner of one window should remember it as such. It should only be
134 // drawn on the owners desktop - not on any other.
135 multi_user_window_manager()->SetWindowOwner(window(0), "A");
136 EXPECT_EQ("A", multi_user_window_manager()->GetWindowOwner(window(0)));
138 multi_user_window_manager()->GetUserPresentingWindow(window(0)));
140 multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
142 multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
144 // Overriding it with another state should show it on the other user's
146 multi_user_window_manager()->ShowWindowForUser(window(0), "B");
147 EXPECT_EQ("A", multi_user_window_manager()->GetWindowOwner(window(0)));
149 multi_user_window_manager()->GetUserPresentingWindow(window(0)));
151 multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
153 multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
156 // Testing simple owner changes.
157 TEST_F(MultiUserWindowManagerTest, OwnerTests) {
158 SetUpForThisManyWindows(5);
159 // Set some windows to the active owner.
160 multi_user_window_manager()->SetWindowOwner(window(0), "A");
161 EXPECT_EQ("S[A], S[], S[], S[], S[]", GetStatus());
162 multi_user_window_manager()->SetWindowOwner(window(2), "A");
163 EXPECT_EQ("S[A], S[], S[A], S[], S[]", GetStatus());
165 // Set some windows to an inactive owner. Note that the windows should hide.
166 multi_user_window_manager()->SetWindowOwner(window(1), "B");
167 EXPECT_EQ("S[A], H[B], S[A], S[], S[]", GetStatus());
168 multi_user_window_manager()->SetWindowOwner(window(3), "B");
169 EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
171 // Assume that the user has now changed to C - which should show / hide
173 multi_user_window_manager()->ActiveUserChanged("C");
174 EXPECT_EQ("H[A], H[B], H[A], H[B], S[]", GetStatus());
176 // If someone tries to show an inactive window it should only work if it can
177 // be shown / hidden.
178 multi_user_window_manager()->ActiveUserChanged("A");
179 EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
181 EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
183 EXPECT_EQ("S[A], H[B], H[A], H[B], S[]", GetStatus());
185 EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
188 TEST_F(MultiUserWindowManagerTest, CloseWindowTests) {
189 SetUpForThisManyWindows(2);
190 multi_user_window_manager()->SetWindowOwner(window(0), "B");
191 EXPECT_EQ("H[B], S[]", GetStatus());
192 multi_user_window_manager()->ShowWindowForUser(window(0), "A");
193 EXPECT_EQ("S[B,A], S[]", GetStatus());
194 EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
196 // Simulate a close of the shared window.
197 multi_user_window_manager()->OnWindowDestroyed(window(0));
199 // There should be no owner anymore for that window and the shared windows
200 // should be gone as well.
201 EXPECT_EQ("S[], S[]", GetStatus());
202 EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
205 TEST_F(MultiUserWindowManagerTest, SharedWindowTests) {
206 SetUpForThisManyWindows(5);
207 // Set some owners and make sure we got what we asked for.
208 multi_user_window_manager()->SetWindowOwner(window(0), "A");
209 multi_user_window_manager()->SetWindowOwner(window(1), "A");
210 multi_user_window_manager()->SetWindowOwner(window(2), "B");
211 multi_user_window_manager()->SetWindowOwner(window(3), "B");
212 multi_user_window_manager()->SetWindowOwner(window(4), "C");
213 EXPECT_EQ("S[A], S[A], H[B], H[B], H[C]", GetStatus());
214 EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
216 // For all following tests we override window 2 to be shown by user B.
217 multi_user_window_manager()->ShowWindowForUser(window(1), "B");
219 // Change window 3 between two users and see that it changes
220 // accordingly (or not).
221 multi_user_window_manager()->ShowWindowForUser(window(2), "A");
222 EXPECT_EQ("S[A], H[A,B], S[B,A], H[B], H[C]", GetStatus());
223 EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
224 multi_user_window_manager()->ShowWindowForUser(window(2), "C");
225 EXPECT_EQ("S[A], H[A,B], H[B,C], H[B], H[C]", GetStatus());
226 EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
228 // Switch the users and see that the results are correct.
229 multi_user_window_manager()->ActiveUserChanged("B");
230 EXPECT_EQ("H[A], S[A,B], H[B,C], S[B], H[C]", GetStatus());
231 multi_user_window_manager()->ActiveUserChanged("C");
232 EXPECT_EQ("H[A], H[A,B], S[B,C], H[B], S[C]", GetStatus());
234 // Showing on the desktop of the already owning user should have no impact.
235 multi_user_window_manager()->ShowWindowForUser(window(4), "C");
236 EXPECT_EQ("H[A], H[A,B], S[B,C], H[B], S[C]", GetStatus());
238 // Changing however a shown window back to the original owner should hide it.
239 multi_user_window_manager()->ShowWindowForUser(window(2), "B");
240 EXPECT_EQ("H[A], H[A,B], H[B], H[B], S[C]", GetStatus());
241 EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
243 // And the change should be "permanent" - switching somewhere else and coming
245 multi_user_window_manager()->ActiveUserChanged("B");
246 EXPECT_EQ("H[A], S[A,B], S[B], S[B], H[C]", GetStatus());
247 multi_user_window_manager()->ActiveUserChanged("C");
248 EXPECT_EQ("H[A], H[A,B], H[B], H[B], S[C]", GetStatus());
250 // After switching window 2 back to its original desktop, all desktops should
252 multi_user_window_manager()->ShowWindowForUser(window(1), "A");
253 EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
256 // Make sure that adding a window to another desktop does not cause harm.
257 TEST_F(MultiUserWindowManagerTest, DoubleSharedWindowTests) {
258 SetUpForThisManyWindows(2);
259 multi_user_window_manager()->SetWindowOwner(window(0), "B");
261 // Add two references to the same window.
262 multi_user_window_manager()->ShowWindowForUser(window(0), "A");
263 multi_user_window_manager()->ShowWindowForUser(window(0), "A");
264 EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
266 // Simulate a close of the shared window.
267 multi_user_window_manager()->OnWindowDestroyed(window(0));
269 // There should be no shares anymore open.
270 EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
273 // Tests that the user's desktop visibility changes get respected. These tests
274 // are required to make sure that our usage of the same feature for showing and
275 // hiding does not interfere with the "normal operation".
276 TEST_F(MultiUserWindowManagerTest, PreserveWindowVisibilityTests) {
277 SetUpForThisManyWindows(5);
278 // Set some owners and make sure we got what we asked for.
279 // Note that we try to cover all combinations in one go.
280 multi_user_window_manager()->SetWindowOwner(window(0), "A");
281 multi_user_window_manager()->SetWindowOwner(window(1), "A");
282 multi_user_window_manager()->SetWindowOwner(window(2), "B");
283 multi_user_window_manager()->SetWindowOwner(window(3), "B");
284 multi_user_window_manager()->ShowWindowForUser(window(2), "A");
285 multi_user_window_manager()->ShowWindowForUser(window(3), "A");
286 EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
288 // Hiding a window should be respected - no matter if it is owned by that user
289 // owned by someone else but shown on that desktop - or not owned.
293 EXPECT_EQ("H[A], S[A], H[B,A], S[B,A], H[]", GetStatus());
295 // Flipping to another user and back should preserve all show / hide states.
296 multi_user_window_manager()->ActiveUserChanged("B");
297 EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], H[]", GetStatus());
299 multi_user_window_manager()->ActiveUserChanged("A");
300 EXPECT_EQ("H[A], S[A], H[B,A], S[B,A], H[]", GetStatus());
302 // After making them visible and switching fore and back everything should be
307 EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
309 multi_user_window_manager()->ActiveUserChanged("B");
310 EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
312 multi_user_window_manager()->ActiveUserChanged("A");
313 EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
315 // Now test that making windows visible through "normal operation" while the
316 // user's desktop is hidden leads to the correct result.
317 multi_user_window_manager()->ActiveUserChanged("B");
318 EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
322 EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
323 multi_user_window_manager()->ActiveUserChanged("A");
324 EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
327 // Check that minimizing a window which is owned by another user will move it
329 TEST_F(MultiUserWindowManagerTest, MinimizeChangesOwnershipBack) {
330 SetUpForThisManyWindows(4);
331 multi_user_window_manager()->SetWindowOwner(window(0), "A");
332 multi_user_window_manager()->SetWindowOwner(window(1), "B");
333 multi_user_window_manager()->SetWindowOwner(window(2), "B");
334 multi_user_window_manager()->ShowWindowForUser(window(1), "A");
335 EXPECT_EQ("S[A], S[B,A], H[B], S[]", GetStatus());
336 EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(window(1),
338 wm::GetWindowState(window(1))->Minimize();
339 EXPECT_EQ("S[A], H[B], H[B], S[]", GetStatus());
340 EXPECT_FALSE(multi_user_window_manager()->IsWindowOnDesktopOfUser(window(1),
343 // Change to user B and make sure that minimizing does not change anything.
344 multi_user_window_manager()->ActiveUserChanged("B");
345 EXPECT_EQ("H[A], H[B], S[B], S[]", GetStatus());
346 wm::GetWindowState(window(1))->Minimize();
347 EXPECT_EQ("H[A], H[B], S[B], S[]", GetStatus());
350 // Check that we cannot transfer the ownership of a minimized window.
351 TEST_F(MultiUserWindowManagerTest, MinimizeSuppressesViewTransfer) {
352 SetUpForThisManyWindows(1);
353 multi_user_window_manager()->SetWindowOwner(window(0), "A");
354 wm::GetWindowState(window(0))->Minimize();
355 EXPECT_EQ("H[A]", GetStatus());
357 // Try to transfer the window to user B - which should get ignored.
358 multi_user_window_manager()->ShowWindowForUser(window(0), "B");
359 EXPECT_EQ("H[A]", GetStatus());
362 // Testing that the activation state changes to the active window.
363 TEST_F(MultiUserWindowManagerTest, ActiveWindowTests) {
364 SetUpForThisManyWindows(4);
366 aura::client::ActivationClient* activation_client =
367 aura::client::GetActivationClient(window(0)->GetRootWindow());
369 // Set some windows to the active owner.
370 multi_user_window_manager()->SetWindowOwner(window(0), "A");
371 multi_user_window_manager()->SetWindowOwner(window(1), "A");
372 multi_user_window_manager()->SetWindowOwner(window(2), "B");
373 multi_user_window_manager()->SetWindowOwner(window(3), "B");
374 EXPECT_EQ("S[A], S[A], H[B], H[B]", GetStatus());
376 // Set the active window for user A to be #1
377 activation_client->ActivateWindow(window(1));
379 // Change to user B and make sure that one of its windows is active.
380 multi_user_window_manager()->ActiveUserChanged("B");
381 EXPECT_EQ("H[A], H[A], S[B], S[B]", GetStatus());
382 EXPECT_TRUE(window(3) == activation_client->GetActiveWindow() ||
383 window(2) == activation_client->GetActiveWindow());
384 // Set the active window for user B now to be #2
385 activation_client->ActivateWindow(window(2));
387 multi_user_window_manager()->ActiveUserChanged("A");
388 EXPECT_EQ(window(1), activation_client->GetActiveWindow());
390 multi_user_window_manager()->ActiveUserChanged("B");
391 EXPECT_EQ(window(2), activation_client->GetActiveWindow());
393 multi_user_window_manager()->ActiveUserChanged("C");
394 EXPECT_EQ(NULL, activation_client->GetActiveWindow());
396 // Now test that a minimized window stays minimized upon switch and back.
397 multi_user_window_manager()->ActiveUserChanged("A");
398 wm::GetWindowState(window(0))->Minimize();
400 multi_user_window_manager()->ActiveUserChanged("B");
401 multi_user_window_manager()->ActiveUserChanged("A");
402 EXPECT_TRUE(wm::GetWindowState(window(0))->IsMinimized());
403 EXPECT_EQ(window(1), activation_client->GetActiveWindow());
406 // Test that Transient windows are handled properly.
407 TEST_F(MultiUserWindowManagerTest, TransientWindows) {
408 SetUpForThisManyWindows(10);
410 // We create a hierarchy like this:
411 // 0 (A) 4 (B) 7 (-) - The top level owned/not owned windows
413 // 1 5 - 6 8 - Transient child of the owned windows.
415 // 2 9 - A transtient child of a transient child.
418 multi_user_window_manager()->SetWindowOwner(window(0), "A");
419 multi_user_window_manager()->SetWindowOwner(window(4), "B");
420 window(0)->AddTransientChild(window(1));
421 // We first attach 2->3 and then 1->2 to see that the ownership gets
422 // properly propagated through the sub tree upon assigning.
423 window(2)->AddTransientChild(window(3));
424 window(1)->AddTransientChild(window(2));
425 window(4)->AddTransientChild(window(5));
426 window(4)->AddTransientChild(window(6));
427 window(7)->AddTransientChild(window(8));
428 window(7)->AddTransientChild(window(9));
430 // By now the hierarchy should have updated itself to show all windows of A
431 // and hide all windows of B. Unowned windows should remain in what ever state
433 EXPECT_EQ("S[A], S[], S[], S[], H[B], H[], H[], S[], S[], S[]", GetStatus());
435 // Trying to show a hidden transient window shouldn't change anything for now.
438 EXPECT_EQ("S[A], S[], S[], S[], H[B], H[], H[], S[], S[], S[]", GetStatus());
440 // Hiding on the other hand a shown window should work and hide also its
441 // children. Note that hide will have an immediate impact on itself and all
442 // transient children. It furthermore should remember this state when the
443 // transient children are removed from its owner later on.
446 EXPECT_EQ("S[A], S[], H[], H[], H[B], H[], H[], S[], S[], H[]", GetStatus());
448 // Switching users and switch back should return to the previous state.
449 multi_user_window_manager()->ActiveUserChanged("B");
450 EXPECT_EQ("H[A], H[], H[], H[], S[B], S[], S[], S[], S[], H[]", GetStatus());
451 multi_user_window_manager()->ActiveUserChanged("A");
452 EXPECT_EQ("S[A], S[], H[], H[], H[B], H[], H[], S[], S[], H[]", GetStatus());
454 // Removing a window from its transient parent should return to the previously
455 // set visibility state.
456 // Note: Window2 was explicitly hidden above and that state should remain.
457 // Note furthermore that Window3 should also be hidden since it was hidden
458 // implicitly by hiding Window2.
459 // set hidden above).
460 // 0 (A) 4 (B) 7 (-) 2(-) 3 (-) 6(-)
465 window(2)->RemoveTransientChild(window(3));
466 window(4)->RemoveTransientChild(window(6));
467 EXPECT_EQ("S[A], S[], H[], H[], H[B], H[], S[], S[], S[], H[]", GetStatus());
468 // Before we leave we need to reverse all transient window ownerships.
469 window(0)->RemoveTransientChild(window(1));
470 window(1)->RemoveTransientChild(window(2));
471 window(4)->RemoveTransientChild(window(5));
472 window(7)->RemoveTransientChild(window(8));
473 window(7)->RemoveTransientChild(window(9));
476 // Test that the initial visibility state gets remembered.
477 TEST_F(MultiUserWindowManagerTest, PreserveInitialVisibility) {
478 SetUpForThisManyWindows(4);
480 // Set our initial show state before we assign an owner.
485 EXPECT_EQ("S[], H[], S[], H[]", GetStatus());
487 // First test: The show state gets preserved upon user switch.
488 multi_user_window_manager()->SetWindowOwner(window(0), "A");
489 multi_user_window_manager()->SetWindowOwner(window(1), "A");
490 multi_user_window_manager()->SetWindowOwner(window(2), "B");
491 multi_user_window_manager()->SetWindowOwner(window(3), "B");
492 EXPECT_EQ("S[A], H[A], H[B], H[B]", GetStatus());
493 multi_user_window_manager()->ActiveUserChanged("B");
494 EXPECT_EQ("H[A], H[A], S[B], H[B]", GetStatus());
495 multi_user_window_manager()->ActiveUserChanged("A");
496 EXPECT_EQ("S[A], H[A], H[B], H[B]", GetStatus());
498 // Second test: Transferring the window to another desktop preserves the
500 multi_user_window_manager()->ShowWindowForUser(window(0), "B");
501 multi_user_window_manager()->ShowWindowForUser(window(1), "B");
502 multi_user_window_manager()->ShowWindowForUser(window(2), "A");
503 multi_user_window_manager()->ShowWindowForUser(window(3), "A");
504 EXPECT_EQ("H[A,B], H[A,B], S[B,A], H[B,A]", GetStatus());
505 multi_user_window_manager()->ActiveUserChanged("B");
506 EXPECT_EQ("S[A,B], H[A,B], H[B,A], H[B,A]", GetStatus());
507 multi_user_window_manager()->ActiveUserChanged("A");
508 EXPECT_EQ("H[A,B], H[A,B], S[B,A], H[B,A]", GetStatus());