blob: d400c7bca63797b4bd198b156935b7c89a037588 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/ash/multi_user_window_manager.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/test_shell_delegate.h"
#include "ash/wm/window_state.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/testing_profile.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/root_window.h"
#include "ui/base/ui_base_types.h"
namespace ash {
namespace test {
// This many test windows will get created.
const int kNumberOfTestWindows = 5;
// A test class for preparing the chrome::MultiUserWindowManager. It creates
// various windows and instantiates the chrome::MultiUserWindowManager.
class MultiUserWindowManagerTest : public AshTestBase {
public:
MultiUserWindowManagerTest() : multi_user_window_manager_(NULL) {}
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
protected:
// Set up the test environment for this many windows.
void SetUpForThisManyWindows(int windows);
// Return the window with the given index.
aura::Window* window(size_t index) {
DCHECK(index < window_.size());
return window_[index];
}
// The accessor to the MultiWindowManager.
chrome::MultiUserWindowManager* multi_user_window_manager() {
return multi_user_window_manager_;
}
// Returns a list of all open windows in the following form:
// "<H(idden)/S(hown)>[<Owner>[,<shownForUser>]], .."
// Like: "S[B], .." would mean that window#0 is shown and belongs to user B.
// or "S[B,A], .." would mean that window#0 is shown, belongs to B but is
// shown by A.
std::string GetStatus();
private:
// These get created for each session.
std::vector<aura::Window*> window_;
// The instance of the MultiUserWindowManager.
chrome::MultiUserWindowManager* multi_user_window_manager_;
DISALLOW_COPY_AND_ASSIGN(MultiUserWindowManagerTest);
};
void MultiUserWindowManagerTest::SetUp() {
CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMultiProfiles);
AshTestBase::SetUp();
}
void MultiUserWindowManagerTest::SetUpForThisManyWindows(int windows) {
DCHECK(!window_.size());
for (int i = 0; i < windows; i++) {
window_.push_back(CreateTestWindowInShellWithId(i));
window_[i]->Show();
}
multi_user_window_manager_ =
chrome::MultiUserWindowManager::CreateInstanceInternal("A");
EXPECT_TRUE(multi_user_window_manager_);
}
void MultiUserWindowManagerTest::TearDown() {
// Since the AuraTestBase is needed to create our assets, we have to
// also delete them before we tear it down.
while (!window_.empty()) {
delete *(window_.begin());
window_.erase(window_.begin());
}
AshTestBase::TearDown();
chrome::MultiUserWindowManager::DeleteInstance();
}
std::string MultiUserWindowManagerTest::GetStatus() {
std::string s;
for (size_t i = 0; i < window_.size(); i++) {
if (i)
s += ", ";
s += window(i)->IsVisible() ? "S[" : "H[";
const std::string& owner =
multi_user_window_manager_->GetWindowOwner(window(i));
s += owner;
const std::string& presenter =
multi_user_window_manager_->GetUserPresentingWindow(window(i));
if (!owner.empty() && owner != presenter) {
s += ",";
s += presenter;
}
s += "]";
}
return s;
}
// Testing basic assumptions like default state and existence of manager.
TEST_F(MultiUserWindowManagerTest, BasicTests) {
SetUpForThisManyWindows(3);
// Check the basic assumptions: All windows are visible and there is no owner.
EXPECT_EQ("S[], S[], S[]", GetStatus());
EXPECT_TRUE(multi_user_window_manager());
EXPECT_EQ(multi_user_window_manager(),
chrome::MultiUserWindowManager::GetInstance());
EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
// The owner of an unowned window should be empty and it should be shown on
// all windows.
EXPECT_EQ("", multi_user_window_manager()->GetWindowOwner(window(0)));
EXPECT_EQ("",
multi_user_window_manager()->GetUserPresentingWindow(window(0)));
EXPECT_TRUE(
multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
EXPECT_TRUE(
multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
// Set the owner of one window should remember it as such. It should only be
// drawn on the owners desktop - not on any other.
multi_user_window_manager()->SetWindowOwner(window(0), "A");
EXPECT_EQ("A", multi_user_window_manager()->GetWindowOwner(window(0)));
EXPECT_EQ("A",
multi_user_window_manager()->GetUserPresentingWindow(window(0)));
EXPECT_TRUE(
multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
EXPECT_FALSE(
multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
// Overriding it with another state should show it on the other user's
// desktop.
multi_user_window_manager()->ShowWindowForUser(window(0), "B");
EXPECT_EQ("A", multi_user_window_manager()->GetWindowOwner(window(0)));
EXPECT_EQ("B",
multi_user_window_manager()->GetUserPresentingWindow(window(0)));
EXPECT_FALSE(
multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
EXPECT_TRUE(
multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
}
// Testing simple owner changes.
TEST_F(MultiUserWindowManagerTest, OwnerTests) {
SetUpForThisManyWindows(5);
// Set some windows to the active owner.
multi_user_window_manager()->SetWindowOwner(window(0), "A");
EXPECT_EQ("S[A], S[], S[], S[], S[]", GetStatus());
multi_user_window_manager()->SetWindowOwner(window(2), "A");
EXPECT_EQ("S[A], S[], S[A], S[], S[]", GetStatus());
// Set some windows to an inactive owner. Note that the windows should hide.
multi_user_window_manager()->SetWindowOwner(window(1), "B");
EXPECT_EQ("S[A], H[B], S[A], S[], S[]", GetStatus());
multi_user_window_manager()->SetWindowOwner(window(3), "B");
EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
// Assume that the user has now changed to C - which should show / hide
// accordingly.
multi_user_window_manager()->ActiveUserChanged("C");
EXPECT_EQ("H[A], H[B], H[A], H[B], S[]", GetStatus());
// If someone tries to show an inactive window it should only work if it can
// be shown / hidden.
multi_user_window_manager()->ActiveUserChanged("A");
EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
window(3)->Show();
EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
window(2)->Hide();
EXPECT_EQ("S[A], H[B], H[A], H[B], S[]", GetStatus());
window(2)->Show();
EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
}
TEST_F(MultiUserWindowManagerTest, CloseWindowTests) {
SetUpForThisManyWindows(2);
multi_user_window_manager()->SetWindowOwner(window(0), "B");
EXPECT_EQ("H[B], S[]", GetStatus());
multi_user_window_manager()->ShowWindowForUser(window(0), "A");
EXPECT_EQ("S[B,A], S[]", GetStatus());
EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
// Simulate a close of the shared window.
multi_user_window_manager()->OnWindowDestroyed(window(0));
// There should be no owner anymore for that window and the shared windows
// should be gone as well.
EXPECT_EQ("S[], S[]", GetStatus());
EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
}
TEST_F(MultiUserWindowManagerTest, SharedWindowTests) {
SetUpForThisManyWindows(5);
// Set some owners and make sure we got what we asked for.
multi_user_window_manager()->SetWindowOwner(window(0), "A");
multi_user_window_manager()->SetWindowOwner(window(1), "A");
multi_user_window_manager()->SetWindowOwner(window(2), "B");
multi_user_window_manager()->SetWindowOwner(window(3), "B");
multi_user_window_manager()->SetWindowOwner(window(4), "C");
EXPECT_EQ("S[A], S[A], H[B], H[B], H[C]", GetStatus());
EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
// For all following tests we override window 2 to be shown by user B.
multi_user_window_manager()->ShowWindowForUser(window(1), "B");
// Change window 3 between two users and see that it changes
// accordingly (or not).
multi_user_window_manager()->ShowWindowForUser(window(2), "A");
EXPECT_EQ("S[A], H[A,B], S[B,A], H[B], H[C]", GetStatus());
EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
multi_user_window_manager()->ShowWindowForUser(window(2), "C");
EXPECT_EQ("S[A], H[A,B], H[B,C], H[B], H[C]", GetStatus());
EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
// Switch the users and see that the results are correct.
multi_user_window_manager()->ActiveUserChanged("B");
EXPECT_EQ("H[A], S[A,B], H[B,C], S[B], H[C]", GetStatus());
multi_user_window_manager()->ActiveUserChanged("C");
EXPECT_EQ("H[A], H[A,B], S[B,C], H[B], S[C]", GetStatus());
// Showing on the desktop of the already owning user should have no impact.
multi_user_window_manager()->ShowWindowForUser(window(4), "C");
EXPECT_EQ("H[A], H[A,B], S[B,C], H[B], S[C]", GetStatus());
// Changing however a shown window back to the original owner should hide it.
multi_user_window_manager()->ShowWindowForUser(window(2), "B");
EXPECT_EQ("H[A], H[A,B], H[B], H[B], S[C]", GetStatus());
EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
// And the change should be "permanent" - switching somewhere else and coming
// back.
multi_user_window_manager()->ActiveUserChanged("B");
EXPECT_EQ("H[A], S[A,B], S[B], S[B], H[C]", GetStatus());
multi_user_window_manager()->ActiveUserChanged("C");
EXPECT_EQ("H[A], H[A,B], H[B], H[B], S[C]", GetStatus());
// After switching window 2 back to its original desktop, all desktops should
// be "clean" again.
multi_user_window_manager()->ShowWindowForUser(window(1), "A");
EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
}
// Make sure that adding a window to another desktop does not cause harm.
TEST_F(MultiUserWindowManagerTest, DoubleSharedWindowTests) {
SetUpForThisManyWindows(2);
multi_user_window_manager()->SetWindowOwner(window(0), "B");
// Add two references to the same window.
multi_user_window_manager()->ShowWindowForUser(window(0), "A");
multi_user_window_manager()->ShowWindowForUser(window(0), "A");
EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
// Simulate a close of the shared window.
multi_user_window_manager()->OnWindowDestroyed(window(0));
// There should be no shares anymore open.
EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
}
// Tests that the user's desktop visibility changes get respected. These tests
// are required to make sure that our usage of the same feature for showing and
// hiding does not interfere with the "normal operation".
TEST_F(MultiUserWindowManagerTest, PreserveWindowVisibilityTests) {
SetUpForThisManyWindows(5);
// Set some owners and make sure we got what we asked for.
// Note that we try to cover all combinations in one go.
multi_user_window_manager()->SetWindowOwner(window(0), "A");
multi_user_window_manager()->SetWindowOwner(window(1), "A");
multi_user_window_manager()->SetWindowOwner(window(2), "B");
multi_user_window_manager()->SetWindowOwner(window(3), "B");
multi_user_window_manager()->ShowWindowForUser(window(2), "A");
multi_user_window_manager()->ShowWindowForUser(window(3), "A");
EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
// Hiding a window should be respected - no matter if it is owned by that user
// owned by someone else but shown on that desktop - or not owned.
window(0)->Hide();
window(2)->Hide();
window(4)->Hide();
EXPECT_EQ("H[A], S[A], H[B,A], S[B,A], H[]", GetStatus());
// Flipping to another user and back should preserve all show / hide states.
multi_user_window_manager()->ActiveUserChanged("B");
EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], H[]", GetStatus());
multi_user_window_manager()->ActiveUserChanged("A");
EXPECT_EQ("H[A], S[A], H[B,A], S[B,A], H[]", GetStatus());
// After making them visible and switching fore and back everything should be
// visible.
window(0)->Show();
window(2)->Show();
window(4)->Show();
EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
multi_user_window_manager()->ActiveUserChanged("B");
EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
multi_user_window_manager()->ActiveUserChanged("A");
EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
// Now test that making windows visible through "normal operation" while the
// user's desktop is hidden leads to the correct result.
multi_user_window_manager()->ActiveUserChanged("B");
EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
window(0)->Show();
window(2)->Show();
window(4)->Show();
EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
multi_user_window_manager()->ActiveUserChanged("A");
EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
}
// Check that minimizing a window which is owned by another user will move it
// back.
TEST_F(MultiUserWindowManagerTest, MinimizeChangesOwnershipBack) {
SetUpForThisManyWindows(4);
multi_user_window_manager()->SetWindowOwner(window(0), "A");
multi_user_window_manager()->SetWindowOwner(window(1), "B");
multi_user_window_manager()->SetWindowOwner(window(2), "B");
multi_user_window_manager()->ShowWindowForUser(window(1), "A");
EXPECT_EQ("S[A], S[B,A], H[B], S[]", GetStatus());
EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(window(1),
"A"));
wm::GetWindowState(window(1))->Minimize();
EXPECT_EQ("S[A], H[B], H[B], S[]", GetStatus());
EXPECT_FALSE(multi_user_window_manager()->IsWindowOnDesktopOfUser(window(1),
"A"));
// Change to user B and make sure that minimizing does not change anything.
multi_user_window_manager()->ActiveUserChanged("B");
EXPECT_EQ("H[A], H[B], S[B], S[]", GetStatus());
wm::GetWindowState(window(1))->Minimize();
EXPECT_EQ("H[A], H[B], S[B], S[]", GetStatus());
}
// Check that we cannot transfer the ownership of a minimized window.
TEST_F(MultiUserWindowManagerTest, MinimizeSuppressesViewTransfer) {
SetUpForThisManyWindows(1);
multi_user_window_manager()->SetWindowOwner(window(0), "A");
wm::GetWindowState(window(0))->Minimize();
EXPECT_EQ("H[A]", GetStatus());
// Try to transfer the window to user B - which should get ignored.
multi_user_window_manager()->ShowWindowForUser(window(0), "B");
EXPECT_EQ("H[A]", GetStatus());
}
} // namespace test
} // namespace ash