Support interrupted animation smoothness reporting
Allow TrayItemView "show" animation smoothness metric to be recorded when the "show" animation interrupts an on-going "hide" animation, and vice versa. Bug: b:294890121 Change-Id: Id8b537430baafd25c17cc7a70a8c5bf926cf4f70 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4766287 Reviewed-by: Andre Le <leandre@chromium.org> Commit-Queue: Elliot Tuck <etuck@chromium.org> Cr-Commit-Position: refs/heads/main@{#1184818}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
787b25420b
commit
18754a5b6a
ash/system/tray
@ -200,14 +200,14 @@ void TrayItemView::PerformVisibilityAnimation(bool visible) {
|
||||
|
||||
if (target_visible_) {
|
||||
SetupThroughputTrackerForAnimationSmoothness(
|
||||
GetWidget(), throughput_tracker_,
|
||||
GetWidget(), show_throughput_tracker_,
|
||||
kShowAnimationSmoothnessHistogramName);
|
||||
animation_->SetSlideDuration(base::Milliseconds(400));
|
||||
animation_->Show();
|
||||
AnimationProgressed(animation_.get());
|
||||
} else {
|
||||
SetupThroughputTrackerForAnimationSmoothness(
|
||||
GetWidget(), throughput_tracker_,
|
||||
GetWidget(), hide_throughput_tracker_,
|
||||
kHideAnimationSmoothnessHistogramName);
|
||||
animation_->SetSlideDuration(base::Milliseconds(100));
|
||||
animation_->Hide();
|
||||
@ -303,10 +303,16 @@ void TrayItemView::AnimationEnded(const gfx::Animation* animation) {
|
||||
views::View::SetVisible(target_visible_);
|
||||
layer()->SetOpacity(target_visible_ ? 1.0 : 0.0);
|
||||
|
||||
if (throughput_tracker_) {
|
||||
// Reset `throughput_tracker_` to reset animation metrics recording.
|
||||
throughput_tracker_->Stop();
|
||||
throughput_tracker_.reset();
|
||||
if (show_throughput_tracker_) {
|
||||
// Reset `show_throughput_tracker_` to reset animation metrics recording.
|
||||
show_throughput_tracker_->Stop();
|
||||
show_throughput_tracker_.reset();
|
||||
}
|
||||
|
||||
if (hide_throughput_tracker_) {
|
||||
// Reset `hide_throughput_tracker_` to reset animation metrics recording.
|
||||
hide_throughput_tracker_->Stop();
|
||||
hide_throughput_tracker_.reset();
|
||||
}
|
||||
|
||||
if (animation_idle_closure_) {
|
||||
|
@ -213,8 +213,11 @@ class ASH_EXPORT TrayItemView : public views::View,
|
||||
raw_ptr<views::ImageView, DanglingUntriaged | ExperimentalAsh> image_view_ =
|
||||
nullptr;
|
||||
|
||||
// Measure animation smoothness metrics for `animation_`.
|
||||
absl::optional<ui::ThroughputTracker> throughput_tracker_;
|
||||
// Measures animation smoothness metrics for "show" animation.
|
||||
absl::optional<ui::ThroughputTracker> show_throughput_tracker_;
|
||||
|
||||
// Measures animation smoothness metrics for "hide" animation.
|
||||
absl::optional<ui::ThroughputTracker> hide_throughput_tracker_;
|
||||
|
||||
// Number of active requests to disable animation.
|
||||
size_t disable_animation_count_ = 0u;
|
||||
|
@ -8,15 +8,61 @@
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "ash/test/ash_test_util.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
#include "ui/compositor/layer.h"
|
||||
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
|
||||
#include "ui/compositor/test/test_utils.h"
|
||||
#include "ui/views/controls/image_view.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
constexpr char kShowAnimationSmoothnessHistogramName[] =
|
||||
"Ash.StatusArea.TrayItemView.Show";
|
||||
constexpr char kHideAnimationSmoothnessHistogramName[] =
|
||||
"Ash.StatusArea.TrayItemView.Hide";
|
||||
} // namespace
|
||||
|
||||
// A class that can be used to wait for the given `TrayItemView`'s visibility
|
||||
// animation to finish (`TrayItemView` does not currently use layer animations,
|
||||
// so we can't just use `ui::LayerAnimationStoppedWaiter`).
|
||||
class TrayItemViewAnimationWaiter {
|
||||
public:
|
||||
explicit TrayItemViewAnimationWaiter(TrayItemView* tray_item)
|
||||
: tray_item_(tray_item) {}
|
||||
TrayItemViewAnimationWaiter(const TrayItemViewAnimationWaiter&) = delete;
|
||||
TrayItemViewAnimationWaiter& operator=(const TrayItemViewAnimationWaiter&) =
|
||||
delete;
|
||||
~TrayItemViewAnimationWaiter() = default;
|
||||
|
||||
// Waits for `tray_item_`'s visibility animation to finish, or no-op if it is
|
||||
// not currently animating.
|
||||
void Wait() {
|
||||
if (tray_item_->IsAnimating()) {
|
||||
tray_item_->SetAnimationIdleClosureForTest(base::BindOnce(
|
||||
&TrayItemViewAnimationWaiter::OnTrayItemAnimationFinished,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
run_loop_.Run();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Called when `tray_item_`'s visibility animation finishes.
|
||||
void OnTrayItemAnimationFinished() { run_loop_.Quit(); }
|
||||
|
||||
// The tray item whose animation is being waited for. Owned by the views
|
||||
// hierarchy.
|
||||
raw_ptr<TrayItemView, ExperimentalAsh> tray_item_ = nullptr;
|
||||
|
||||
base::RunLoop run_loop_;
|
||||
|
||||
base::WeakPtrFactory<TrayItemViewAnimationWaiter> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
class TestTrayItemView : public TrayItemView {
|
||||
public:
|
||||
explicit TestTrayItemView(Shelf* shelf) : TrayItemView(shelf) {}
|
||||
@ -52,6 +98,18 @@ class TrayItemViewTest : public AshTestBase {
|
||||
AshTestBase::TearDown();
|
||||
}
|
||||
|
||||
// Helper function that waits not only for `tray_item()`'s animation to finish
|
||||
// but also for any animation throughput data to be passed from cc to ui.
|
||||
void WaitForAnimation() {
|
||||
TrayItemViewAnimationWaiter waiter(tray_item());
|
||||
waiter.Wait();
|
||||
|
||||
// Ensure there is one more frame presented after animation finishes to
|
||||
// allow animation throughput data to be passed from cc to ui.
|
||||
EXPECT_TRUE(ui::WaitForNextFrameToBePresented(
|
||||
tray_item()->GetWidget()->GetCompositor()));
|
||||
}
|
||||
|
||||
views::Widget* widget() { return widget_.get(); }
|
||||
TrayItemView* tray_item() { return tray_item_; }
|
||||
|
||||
@ -163,4 +221,88 @@ TEST_F(TrayItemViewTest, LargeImageIcon) {
|
||||
EXPECT_EQ(tray_item()->CalculatePreferredSize(), kLargeImageSize);
|
||||
}
|
||||
|
||||
// Tests that a smoothness metric is recorded for the "show" animation.
|
||||
TEST_F(TrayItemViewTest, SmoothnessMetricRecordedForShowAnimation) {
|
||||
// Start with the tray item hidden. Note that animations still complete
|
||||
// immediately in this part of the test, so no smoothness metrics are emitted.
|
||||
tray_item()->SetVisible(false);
|
||||
base::HistogramTester histogram_tester;
|
||||
histogram_tester.ExpectTotalCount(kHideAnimationSmoothnessHistogramName, 0);
|
||||
|
||||
// Set the animation duration scale to a non-zero value for the rest of the
|
||||
// test. Smoothness metrics should be emitted from this point onward.
|
||||
ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
|
||||
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
|
||||
|
||||
// Start the tray item's "show" animation and wait for it to finish.
|
||||
tray_item()->SetVisible(true);
|
||||
WaitForAnimation();
|
||||
|
||||
// Verify that the "show" animation's smoothness metric was recorded.
|
||||
histogram_tester.ExpectTotalCount(kShowAnimationSmoothnessHistogramName, 1);
|
||||
}
|
||||
|
||||
// Tests that a smoothness metric is recorded for the "hide" animation.
|
||||
TEST_F(TrayItemViewTest, SmoothnessMetricRecordedForHideAnimation) {
|
||||
base::HistogramTester histogram_tester;
|
||||
histogram_tester.ExpectTotalCount(kHideAnimationSmoothnessHistogramName, 0);
|
||||
|
||||
// Set the animation duration scale to a non-zero value for the rest of the
|
||||
// test. Smoothness metrics should be emitted from this point onward.
|
||||
ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
|
||||
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
|
||||
|
||||
// Start the tray item's "hide" animation and wait for it to finish.
|
||||
tray_item()->SetVisible(false);
|
||||
WaitForAnimation();
|
||||
|
||||
// Verify that the "hide" animation's smoothness metric was recorded.
|
||||
histogram_tester.ExpectTotalCount(kHideAnimationSmoothnessHistogramName, 1);
|
||||
}
|
||||
|
||||
// Tests that the smoothness metric for the "hide" animation is still recorded
|
||||
// even when the "hide" animation interrupts the "show" animation.
|
||||
TEST_F(TrayItemViewTest, HideSmoothnessMetricRecordedWhenHideInterruptsShow) {
|
||||
// Start with the tray item hidden. Note that animations still complete
|
||||
// immediately in this part of the test, so no smoothness metrics are emitted.
|
||||
tray_item()->SetVisible(false);
|
||||
base::HistogramTester histogram_tester;
|
||||
histogram_tester.ExpectTotalCount(kHideAnimationSmoothnessHistogramName, 0);
|
||||
|
||||
// Set the animation duration scale to a non-zero value for the rest of the
|
||||
// test. Smoothness metrics should be emitted from this point onward.
|
||||
ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
|
||||
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
|
||||
|
||||
// Start the tray item's "show" animation, but interrupt it with the "hide"
|
||||
// animation. Wait for the "hide" animation to complete.
|
||||
tray_item()->SetVisible(true);
|
||||
tray_item()->SetVisible(false);
|
||||
WaitForAnimation();
|
||||
|
||||
// Verify that the "hide" animation's smoothness metric was recorded.
|
||||
histogram_tester.ExpectTotalCount(kHideAnimationSmoothnessHistogramName, 1);
|
||||
}
|
||||
|
||||
// Tests that the smoothness metric for the "show" animation is still recorded
|
||||
// even when the "show" animation interrupts the "hide" animation.
|
||||
TEST_F(TrayItemViewTest, ShowSmoothnessMetricRecordedWhenShowInterruptsHide) {
|
||||
base::HistogramTester histogram_tester;
|
||||
histogram_tester.ExpectTotalCount(kHideAnimationSmoothnessHistogramName, 0);
|
||||
|
||||
// Set the animation duration scale to a non-zero value for the rest of the
|
||||
// test. Smoothness metrics should be emitted from this point onward.
|
||||
ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
|
||||
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
|
||||
|
||||
// Start the tray item's "hide" animation, but interrupt it with the "show"
|
||||
// animation. Wait for the "show" animation to complete.
|
||||
tray_item()->SetVisible(false);
|
||||
tray_item()->SetVisible(true);
|
||||
WaitForAnimation();
|
||||
|
||||
// Verify that the "show" animation's smoothness metric was recorded.
|
||||
histogram_tester.ExpectTotalCount(kShowAnimationSmoothnessHistogramName, 1);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
Reference in New Issue
Block a user