1 // Copyright 2019 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 #include "ui/views/animation/compositor_animation_runner.h"
6
7 #include "base/test/bind_test_util.h"
8 #include "base/timer/timer.h"
9 #include "ui/compositor/animation_metrics_reporter.h"
10 #include "ui/compositor/test/draw_waiter_for_test.h"
11 #include "ui/gfx/animation/linear_animation.h"
12 #include "ui/views/animation/animation_delegate_views.h"
13 #include "ui/views/buildflags.h"
14 #include "ui/views/test/widget_test.h"
15
16 namespace views {
17 namespace test {
18 namespace {
19 constexpr base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(100);
20 }
21
22 using CompositorAnimationRunnerTest = WidgetTest;
23
TEST_F(CompositorAnimationRunnerTest,BasicCoverageTest)24 TEST_F(CompositorAnimationRunnerTest, BasicCoverageTest) {
25 WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
26 widget->Show();
27
28 AnimationDelegateViews delegate(widget->GetContentsView());
29 gfx::LinearAnimation animation(
30 kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
31
32 base::RepeatingTimer interval_timer;
33 base::RunLoop run_loop;
34
35 animation.Start();
36 EXPECT_TRUE(animation.is_animating());
37 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
38
39 interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
40 if (animation.is_animating())
41 return;
42
43 interval_timer.Stop();
44 run_loop.Quit();
45 }));
46
47 run_loop.Run();
48 }
49
50 namespace {
51
52 class TestAnimationMetricsReporter : public ui::AnimationMetricsReporter {
53 public:
54 TestAnimationMetricsReporter() = default;
55 TestAnimationMetricsReporter(TestAnimationMetricsReporter&) = delete;
56 TestAnimationMetricsReporter& operator=(TestAnimationMetricsReporter&) =
57 delete;
58 ~TestAnimationMetricsReporter() override = default;
59
60 // ui::AnimationMetricsReporter:
Report(int value)61 void Report(int value) override { ++report_count_; }
62
report_count() const63 int report_count() const { return report_count_; }
64
65 private:
66 int report_count_ = 0;
67 };
68
69 // Test AnimationDelegateView which has a non-zero expected animation duration
70 // time, which is required for getting smoothness reports.
71 class TestAnimationDelegateViews : public AnimationDelegateViews {
72 public:
TestAnimationDelegateViews(View * view)73 explicit TestAnimationDelegateViews(View* view)
74 : AnimationDelegateViews(view) {}
75 TestAnimationDelegateViews(TestAnimationDelegateViews&) = delete;
76 TestAnimationDelegateViews& operator=(TestAnimationDelegateViews&) = delete;
77 ~TestAnimationDelegateViews() override = default;
78
79 // AnimationDelegateViews:
GetAnimationDurationForReporting() const80 base::TimeDelta GetAnimationDurationForReporting() const override {
81 return kDuration;
82 }
83 };
84
85 } // namespace
86
87 // Tests that an attached animation metrics reporter will get smoothness
88 // reports.
TEST_F(CompositorAnimationRunnerTest,AnimationMetricsReporter)89 TEST_F(CompositorAnimationRunnerTest, AnimationMetricsReporter) {
90 WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
91 widget->Show();
92
93 ui::DrawWaiterForTest::WaitForCompositingStarted(widget->GetCompositor());
94
95 TestAnimationMetricsReporter metrics_reporter;
96 TestAnimationMetricsReporter metrics_reporter2;
97 TestAnimationDelegateViews delegate(widget->GetContentsView());
98 delegate.SetAnimationMetricsReporter(&metrics_reporter);
99 gfx::LinearAnimation animation(
100 kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
101
102 base::RepeatingTimer interval_timer;
103 base::RunLoop run_loop;
104
105 animation.Start();
106 EXPECT_TRUE(animation.is_animating());
107 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
108
109 interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
110 if (animation.is_animating())
111 return;
112
113 interval_timer.Stop();
114 run_loop.Quit();
115 }));
116 run_loop.Run();
117 EXPECT_EQ(1, metrics_reporter.report_count());
118 EXPECT_EQ(0, metrics_reporter2.report_count());
119
120 // Tests that switching metrics reporters for the next animation works as
121 // expected.
122 base::RunLoop run_loop2;
123 delegate.SetAnimationMetricsReporter(&metrics_reporter2);
124 animation.Start();
125 EXPECT_TRUE(animation.is_animating());
126
127 interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
128 if (animation.is_animating())
129 return;
130
131 interval_timer.Stop();
132 run_loop2.Quit();
133 }));
134 run_loop2.Run();
135 EXPECT_EQ(1, metrics_reporter.report_count());
136 EXPECT_EQ(1, metrics_reporter2.report_count());
137 }
138
139 // No DesktopAura on ChromeOS.
140 // Each widget on MACOSX has its own ui::Compositor.
141 #if BUILDFLAG(ENABLE_DESKTOP_AURA)
142 using CompositorAnimationRunnerDesktopTest = DesktopWidgetTest;
143
TEST_F(CompositorAnimationRunnerDesktopTest,SwitchCompositor)144 TEST_F(CompositorAnimationRunnerDesktopTest, SwitchCompositor) {
145 WidgetAutoclosePtr widget1(CreateTopLevelNativeWidget());
146 widget1->Show();
147
148 WidgetAutoclosePtr widget2(CreateTopLevelNativeWidget());
149 widget2->Show();
150
151 ASSERT_NE(widget1->GetCompositor(), widget2->GetCompositor());
152
153 Widget* child = CreateChildNativeWidgetWithParent(widget1.get());
154 child->Show();
155 AnimationDelegateViews delegate(child->GetContentsView());
156 gfx::LinearAnimation animation(
157 kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
158
159 base::RepeatingTimer interval_timer;
160
161 animation.Start();
162 EXPECT_TRUE(animation.is_animating());
163 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
164 {
165 base::RunLoop run_loop;
166 interval_timer.Start(FROM_HERE, kDuration,
167 base::BindLambdaForTesting([&]() {
168 if (animation.is_animating())
169 return;
170 interval_timer.Stop();
171 run_loop.Quit();
172 }));
173 run_loop.Run();
174 }
175
176 EXPECT_FALSE(animation.is_animating());
177
178 Widget::ReparentNativeView(child->GetNativeView(), widget2->GetNativeView());
179 widget1.reset();
180
181 animation.Start();
182 EXPECT_TRUE(animation.is_animating());
183 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
184
185 {
186 base::RunLoop run_loop;
187 interval_timer.Start(FROM_HERE, kDuration,
188 base::BindLambdaForTesting([&]() {
189 if (animation.is_animating())
190 return;
191
192 interval_timer.Stop();
193 run_loop.Quit();
194 }));
195
196 run_loop.Run();
197 }
198 }
199 #endif
200
201 } // namespace test
202 } // namespace views
203