blob: ffc5afdfe9354b3f5059e2eb755c514dc4e2c49b [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/utility/occlusion_tracker_pauser.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "ui/aura/env.h"
#include "ui/aura/window_occlusion_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/test/begin_main_frame_waiter.h"
namespace ash {
namespace {
class TestObserver final : public ui::CompositorAnimationObserver {
public:
TestObserver() = default;
TestObserver(const TestObserver&) = delete;
TestObserver& operator=(const TestObserver&) = delete;
~TestObserver() override = default;
// ui::CompositorAnimationObserver:
void OnAnimationStep(base::TimeTicks timestamp) override {}
void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
};
} // namespace
class OcclusionTrackerPauserTest : public AshTestBase {
public:
OcclusionTrackerPauserTest()
: AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
~OcclusionTrackerPauserTest() override = default;
};
TEST_F(OcclusionTrackerPauserTest, Basic) {
aura::WindowOcclusionTracker* tracker =
aura::Env::GetInstance()->GetWindowOcclusionTracker();
ASSERT_FALSE(tracker->IsPaused());
Shell::Get()->occlusion_tracker_pauser()->PauseUntilAnimationsEnd(
base::TimeDelta());
EXPECT_TRUE(tracker->IsPaused());
auto* compositor = Shell::GetPrimaryRootWindow()->GetHost()->compositor();
TestObserver observer1, observer2;
compositor->AddAnimationObserver(&observer1);
EXPECT_TRUE(tracker->IsPaused());
compositor->RemoveAnimationObserver(&observer1);
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor).Wait();
EXPECT_FALSE(tracker->IsPaused());
compositor->AddAnimationObserver(&observer1);
EXPECT_FALSE(tracker->IsPaused());
Shell::Get()->occlusion_tracker_pauser()->PauseUntilAnimationsEnd(
base::TimeDelta());
EXPECT_TRUE(tracker->IsPaused());
compositor->AddAnimationObserver(&observer2);
EXPECT_TRUE(tracker->IsPaused());
compositor->RemoveAnimationObserver(&observer2);
EXPECT_TRUE(tracker->IsPaused());
compositor->RemoveAnimationObserver(&observer1);
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor).Wait();
EXPECT_FALSE(tracker->IsPaused());
}
TEST_F(OcclusionTrackerPauserTest, MultiDisplay) {
aura::WindowOcclusionTracker* tracker =
aura::Env::GetInstance()->GetWindowOcclusionTracker();
UpdateDisplay("800x1000, 800x1000");
auto* compositor1 = Shell::GetAllRootWindows()[0]->GetHost()->compositor();
auto* compositor2 = Shell::GetAllRootWindows()[1]->GetHost()->compositor();
TestObserver observer1, observer2;
Shell::Get()->occlusion_tracker_pauser()->PauseUntilAnimationsEnd(
base::TimeDelta());
EXPECT_TRUE(tracker->IsPaused());
compositor1->AddAnimationObserver(&observer1);
compositor2->AddAnimationObserver(&observer2);
EXPECT_TRUE(tracker->IsPaused());
compositor1->RemoveAnimationObserver(&observer1);
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor1).Wait();
// Tracker should still be paused.
EXPECT_TRUE(tracker->IsPaused());
compositor2->RemoveAnimationObserver(&observer2);
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor2).Wait();
EXPECT_FALSE(tracker->IsPaused());
// Disconnect display.
Shell::Get()->occlusion_tracker_pauser()->PauseUntilAnimationsEnd(
base::TimeDelta());
EXPECT_TRUE(tracker->IsPaused());
compositor1->AddAnimationObserver(&observer1);
compositor2->AddAnimationObserver(&observer2);
EXPECT_TRUE(tracker->IsPaused());
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor1).Wait();
// Tracker should still be paused.
EXPECT_TRUE(tracker->IsPaused());
compositor1->RemoveAnimationObserver(&observer1);
EXPECT_TRUE(tracker->IsPaused());
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor1).Wait();
EXPECT_TRUE(tracker->IsPaused());
UpdateDisplay("800x1000");
EXPECT_TRUE(tracker->IsPaused());
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor1).Wait();
EXPECT_FALSE(tracker->IsPaused());
}
TEST_F(OcclusionTrackerPauserTest, MultiDisplaySingleAnimatingCompositor) {
aura::WindowOcclusionTracker* tracker =
aura::Env::GetInstance()->GetWindowOcclusionTracker();
UpdateDisplay("800x1000, 800x1000");
auto* compositor1 = Shell::GetAllRootWindows()[0]->GetHost()->compositor();
TestObserver observer1;
Shell::Get()->occlusion_tracker_pauser()->PauseUntilAnimationsEnd(
base::TimeDelta());
EXPECT_TRUE(tracker->IsPaused());
compositor1->AddAnimationObserver(&observer1);
EXPECT_TRUE(tracker->IsPaused());
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor1).Wait();
EXPECT_TRUE(tracker->IsPaused());
compositor1->RemoveAnimationObserver(&observer1);
EXPECT_TRUE(tracker->IsPaused());
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter(compositor1).Wait();
// There are no more animations, so expect the tracker to be unpaused.
EXPECT_FALSE(tracker->IsPaused());
}
TEST_F(OcclusionTrackerPauserTest, Timeout) {
aura::WindowOcclusionTracker* tracker =
aura::Env::GetInstance()->GetWindowOcclusionTracker();
UpdateDisplay("800x1000, 800x1000");
auto* compositor1 = Shell::GetAllRootWindows()[0]->GetHost()->compositor();
auto* compositor2 = Shell::GetAllRootWindows()[1]->GetHost()->compositor();
// Add observer to emulate animations start/end.
TestObserver observer1, observer2;
Shell::Get()->occlusion_tracker_pauser()->PauseUntilAnimationsEnd(
base::Seconds(2));
EXPECT_TRUE(tracker->IsPaused());
compositor1->AddAnimationObserver(&observer1);
compositor2->AddAnimationObserver(&observer2);
EXPECT_TRUE(tracker->IsPaused());
// Wait for BeginFrame since compositor animation notifications happen
// on BeginFrame.
ui::BeginMainFrameWaiter waiter1(compositor1);
ui::BeginMainFrameWaiter waiter2(compositor2);
waiter1.Wait();
waiter2.Wait();
task_environment()->FastForwardBy(base::Seconds(1));
EXPECT_TRUE(tracker->IsPaused());
task_environment()->FastForwardBy(base::Seconds(2));
EXPECT_FALSE(tracker->IsPaused());
compositor1->RemoveAnimationObserver(&observer1);
compositor2->RemoveAnimationObserver(&observer2);
}
} // namespace ash