[go: up one dir, main page]

[Merge to M-76] Virtual Desks: Fix multi-profile behavior

- Windows from an inactive user should not show in the desk's
  mini_view.
- Regardless of the their desks, windows of the inactive user
  should remain hidden.

TBR=jamescook@chromium.org
BUG=972765
TEST=Manual, added new test.

(cherry picked from commit 36e697d0e450ad340c119570edade7449011c109)

Change-Id: I0dc3b7b65fce390430b5a4b8c1ae11b74b831311
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1653839
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: James Cook <jamescook@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#668181}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1659855
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/branch-heads/3809@{#309}
Cr-Branched-From: d82dec1a818f378c464ba307ddd9c92133eac355-refs/heads/master@{#665002}
diff --git a/ash/multi_user/multi_user_window_manager_impl.cc b/ash/multi_user/multi_user_window_manager_impl.cc
index 22188ba..63167d1 100644
--- a/ash/multi_user/multi_user_window_manager_impl.cc
+++ b/ash/multi_user/multi_user_window_manager_impl.cc
@@ -15,6 +15,7 @@
 #include "ash/public/cpp/wallpaper_user_info.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "ash/wm/desks/desks_util.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/auto_reset.h"
 #include "base/macros.h"
@@ -448,7 +449,7 @@
     aura::Window* window,
     bool visible,
     base::TimeDelta animation_time) {
-  if (window->IsVisible() == visible)
+  if (desks_util::BelongsToActiveDesk(window) && window->IsVisible() == visible)
     return;
 
   // Hiding a system modal dialog should not be allowed. Instead we switch to
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc
index f4c44e59..46c2a6d 100644
--- a/ash/wm/desks/desk_preview_view.cc
+++ b/ash/wm/desks/desk_preview_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/desks/desk_preview_view.h"
 
+#include "ash/multi_user/multi_user_window_manager_impl.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/wallpaper/wallpaper_base_view.h"
 #include "ash/wm/desks/desk_mini_view.h"
@@ -43,6 +44,24 @@
   bool should_reset_transform = false;
 };
 
+// Returns true if |window| can be shown in the desk's preview according to its
+// multi-profile ownership status (i.e. can only be shown if it belongs to the
+// active user).
+bool CanShowWindowForMultiProfile(aura::Window* window) {
+  MultiUserWindowManager* multi_user_window_manager =
+      MultiUserWindowManagerImpl::Get();
+  if (!multi_user_window_manager)
+    return true;
+
+  const AccountId account_id =
+      multi_user_window_manager->GetUserPresentingWindow(window);
+  // An empty account ID is returned if the window is presented for all users.
+  if (!account_id.is_valid())
+    return true;
+
+  return account_id == multi_user_window_manager->CurrentAccountId();
+}
+
 // Recursively mirrors |source_layer| and its children and adds them as children
 // of |parent|, taking into account the given |layers_data|.
 void MirrorLayerTree(ui::Layer* source_layer,
@@ -93,6 +112,11 @@
     return;
   }
 
+  if (!CanShowWindowForMultiProfile(window)) {
+    layer_data.should_skip_layer = true;
+    return;
+  }
+
   // Windows transformed into position in the overview mode grid should be
   // mirrored and the transforms of the mirrored layers should be reset to
   // identity.
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 8694d4b..6f5dc4f5 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -4,7 +4,10 @@
 
 #include <vector>
 
+#include "ash/multi_user/multi_user_window_manager_impl.h"
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/multi_user_window_manager.h"
+#include "ash/public/cpp/multi_user_window_manager_delegate.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/window_factory.h"
@@ -1250,6 +1253,120 @@
                 ->current_indicator_state());
 }
 
+namespace {
+
+constexpr char kUser1Email[] = "user1@desks";
+constexpr char kUser2Email[] = "user2@desks";
+
+}  // namespace
+
+class DesksMultiUserTest : public NoSessionAshTestBase,
+                           public MultiUserWindowManagerDelegate {
+ public:
+  DesksMultiUserTest() = default;
+  ~DesksMultiUserTest() override = default;
+
+  MultiUserWindowManager* multi_user_window_manager() {
+    return multi_user_window_manager_.get();
+  }
+
+  // AshTestBase:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(features::kVirtualDesks);
+
+    NoSessionAshTestBase::SetUp();
+    TestSessionControllerClient* session_controller =
+        GetSessionControllerClient();
+    session_controller->Reset();
+    session_controller->AddUserSession(kUser1Email);
+    session_controller->AddUserSession(kUser2Email);
+
+    // Simulate user 1 login.
+    SwitchActiveUser(GetUser1AccountId());
+    multi_user_window_manager_ =
+        MultiUserWindowManager::Create(this, GetUser1AccountId());
+    MultiUserWindowManagerImpl::Get()->SetAnimationSpeedForTest(
+        MultiUserWindowManagerImpl::ANIMATION_SPEED_DISABLED);
+  }
+
+  void TearDown() override {
+    multi_user_window_manager_.reset();
+    NoSessionAshTestBase::TearDown();
+  }
+
+  // MultiUserWindowManagerDelegate:
+  void OnWindowOwnerEntryChanged(aura::Window* window,
+                                 const AccountId& account_id,
+                                 bool was_minimized,
+                                 bool teleported) override {}
+  void OnTransitionUserShelfToNewAccount() override {}
+
+  AccountId GetUser1AccountId() const {
+    return AccountId::FromUserEmail(kUser1Email);
+  }
+
+  AccountId GetUser2AccountId() const {
+    return AccountId::FromUserEmail(kUser2Email);
+  }
+
+  void SwitchActiveUser(const AccountId& account_id) {
+    GetSessionControllerClient()->SwitchActiveUser(account_id);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<MultiUserWindowManager> multi_user_window_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(DesksMultiUserTest);
+};
+
+TEST_F(DesksMultiUserTest, SwitchUsersBackAndForth) {
+  // Create two desks with two windows on each, one window that belongs to the
+  // first user, and the other belongs to the second.
+  auto* controller = DesksController::Get();
+  controller->NewDesk();
+  ASSERT_EQ(2u, controller->desks().size());
+  Desk* desk_1 = controller->desks()[0].get();
+  Desk* desk_2 = controller->desks()[1].get();
+  auto win0 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
+  multi_user_window_manager()->SetWindowOwner(win0.get(), GetUser1AccountId());
+  EXPECT_TRUE(win0->IsVisible());
+  ActivateDesk(desk_2);
+  auto win1 = CreateTestWindow(gfx::Rect(50, 50, 200, 200));
+  multi_user_window_manager()->SetWindowOwner(win1.get(), GetUser1AccountId());
+  EXPECT_FALSE(win0->IsVisible());
+  EXPECT_TRUE(win1->IsVisible());
+
+  // Switch to user_2 and expect no windows from user_1 is visible regardless of
+  // the desk.
+  SwitchActiveUser(GetUser2AccountId());
+  EXPECT_FALSE(win0->IsVisible());
+  EXPECT_FALSE(win1->IsVisible());
+
+  auto win2 = CreateTestWindow(gfx::Rect(0, 0, 250, 200));
+  multi_user_window_manager()->SetWindowOwner(win2.get(), GetUser2AccountId());
+  EXPECT_TRUE(win2->IsVisible());
+  ActivateDesk(desk_1);
+  auto win3 = CreateTestWindow(gfx::Rect(0, 0, 250, 200));
+  multi_user_window_manager()->SetWindowOwner(win3.get(), GetUser2AccountId());
+  EXPECT_FALSE(win0->IsVisible());
+  EXPECT_FALSE(win1->IsVisible());
+  EXPECT_FALSE(win2->IsVisible());
+  EXPECT_TRUE(win3->IsVisible());
+
+  // Similarly when switching back to user_1.
+  SwitchActiveUser(GetUser1AccountId());
+  EXPECT_TRUE(win0->IsVisible());
+  EXPECT_FALSE(win1->IsVisible());
+  EXPECT_FALSE(win2->IsVisible());
+  EXPECT_FALSE(win3->IsVisible());
+  ActivateDesk(desk_2);
+  EXPECT_FALSE(win0->IsVisible());
+  EXPECT_TRUE(win1->IsVisible());
+  EXPECT_FALSE(win2->IsVisible());
+  EXPECT_FALSE(win3->IsVisible());
+}
+
 // TODO(afakhry): Add more tests:
 // - Always on top windows are not tracked by any desk.
 // - Reusing containers when desks are removed and created.