chromium/ash/ambient/ui/media_string_view_unittest.cc

// Copyright 2020 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/ambient/ui/media_string_view.h"

#include <string>

#include "ash/ambient/ambient_constants.h"
#include "ash/ambient/test/ambient_ash_test_base.h"
#include "ash/ambient/ui/ambient_container_view.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/shell.h"
#include "base/strings/utf_string_conversions.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/views/controls/label.h"
#include "ui/views/test/views_test_utils.h"

namespace ash {

class MediaStringViewTest : public AmbientAshTestBase {
 public:
  MediaStringViewTest() : AmbientAshTestBase() {}
  ~MediaStringViewTest() override = default;

  // AmbientAshTestBase:
  void SetUp() override {
    AmbientAshTestBase::SetUp();
    GetSessionControllerClient()->set_show_lock_screen_views(true);
  }

  void TearDown() override {
    CloseAmbientScreen();
    AmbientAshTestBase::TearDown();
  }

  const std::u16string& GetText() {
    return GetMediaStringViewTextLabel()->GetText();
  }
};

TEST_F(MediaStringViewTest, ShowMediaTitleAndArtist) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"artist";

  SimulateMediaMetadataChanged(metadata);

  const std::u16string expected_text = u"title \u2022 artist";
  EXPECT_EQ(GetMediaStringViewTextLabel()->GetText(), expected_text);
}

TEST_F(MediaStringViewTest, TextContainerFitsWidthOfShortText) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"artist";

  SimulateMediaMetadataChanged(metadata);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_EQ(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            GetMediaStringViewTextContainer()->GetPreferredSize().width());
}

TEST_F(MediaStringViewTest, TextContainerHasMaxWidthWithLongText) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";

  SimulateMediaMetadataChanged(metadata);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_EQ(kMediaStringMaxWidthDip,
            GetMediaStringViewTextContainer()->GetPreferredSize().width());
}

TEST_F(MediaStringViewTest, HasNoAnimationWithShortText) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);

  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"name";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
}

TEST_F(MediaStringViewTest, HasAnimationWithLongText) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);

  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_TRUE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
}

TEST_F(MediaStringViewTest, ShouldStopAndStartAnimationWhenTextChanges) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);

  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_TRUE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());

  // Change to another long text.
  metadata.title = u"Another super duper long title";
  metadata.artist = u"Another super duper long artist name";
  SimulateMediaMetadataChanged(metadata);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_TRUE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
}

TEST_F(MediaStringViewTest, ShouldStartAndStopAnimationWhenTextChanges) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);

  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"name";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());

  // Change to long text.
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";
  SimulateMediaMetadataChanged(metadata);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_TRUE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());

  // Change to short text.
  metadata.title = u"title";
  metadata.artist = u"name";
  SimulateMediaMetadataChanged(metadata);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
}

TEST_F(MediaStringViewTest, PauseMediaWillNotStopAnimationWithLongText) {
  ui::ScopedAnimationDurationScaleMode test_duration_mode(
      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);

  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);

  EXPECT_FALSE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
  task_environment()->FastForwardBy(base::Milliseconds(100));
  EXPECT_TRUE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPaused);
  EXPECT_FALSE(GetMediaStringView()->GetVisible());
  EXPECT_TRUE(
      GetMediaStringViewTextLabel()->layer()->GetAnimator()->is_animating());
}

TEST_F(MediaStringViewTest, HasNoMaskLayerWithShortText) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"artist";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);
  // Force re-layout.
  for (auto* view : GetContainerViews())
    views::test::RunScheduledLayout(view);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_TRUE(
      GetMediaStringViewTextContainer()->layer()->gradient_mask().IsEmpty());
}

TEST_F(MediaStringViewTest, HasMaskLayerWithLongText) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);
  // Force re-layout.
  for (auto* view : GetContainerViews())
    views::test::RunScheduledLayout(view);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_FALSE(
      GetMediaStringViewTextContainer()->layer()->gradient_mask().IsEmpty());
}

TEST_F(MediaStringViewTest, MaskLayerShouldUpdate) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"artist";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);
  // Force re-layout.
  for (auto* view : GetContainerViews())
    views::test::RunScheduledLayout(view);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_TRUE(
      GetMediaStringViewTextContainer()->layer()->gradient_mask().IsEmpty());

  // Change to long text.
  metadata.title = u"A super duper long title";
  metadata.artist = u"A super duper long artist name";

  SimulateMediaMetadataChanged(metadata);
  // Force re-layout.
  for (auto* view : GetContainerViews())
    views::test::RunScheduledLayout(view);

  EXPECT_GT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_FALSE(
      GetMediaStringViewTextContainer()->layer()->gradient_mask().IsEmpty());

  // Change to short text.
  metadata.title = u"title";
  metadata.artist = u"artist";

  SimulateMediaMetadataChanged(metadata);
  // Force re-layout.
  for (auto* view : GetContainerViews())
    views::test::RunScheduledLayout(view);

  EXPECT_LT(GetMediaStringViewTextLabel()
                ->GetPreferredSize(views::SizeBounds(
                    GetMediaStringViewTextLabel()->width(), {}))
                .width(),
            kMediaStringMaxWidthDip);
  EXPECT_TRUE(
      GetMediaStringViewTextContainer()->layer()->gradient_mask().IsEmpty());
}

TEST_F(MediaStringViewTest, ShowWhenMediaIsPlaying) {
  SetAmbientShownAndWaitForWidgets();
  EXPECT_FALSE(GetMediaStringView()->GetVisible());

  // Sets media playstate for the current session.
  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  EXPECT_TRUE(GetMediaStringView()->GetVisible());
}

TEST_F(MediaStringViewTest, DoNotShowWhenMediaIsPaused) {
  SetAmbientShownAndWaitForWidgets();
  EXPECT_FALSE(GetMediaStringView()->GetVisible());

  // Sets media playstate for the current session.
  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  EXPECT_TRUE(GetMediaStringView()->GetVisible());

  // Simulates the ongoing media paused.
  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPaused);
  EXPECT_FALSE(GetMediaStringView()->GetVisible());
}

TEST_F(MediaStringViewTest, DoNotShowOnLockScreenIfPrefIsDisabled) {
  // Disables user preference for media controls.
  PrefService* pref =
      Shell::Get()->session_controller()->GetPrimaryUserPrefService();
  pref->SetBoolean(prefs::kLockScreenMediaControlsEnabled, false);
  // Simulates Ambient Mode shown on lock-screen.
  LockScreen();
  FastForwardByLockScreenInactivityTimeout();
  FastForwardTiny();

  // Simulates active and playing media session.
  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);

  // Verifies media string is hidden.
  EXPECT_FALSE(GetMediaStringView()->GetVisible());
}

TEST_F(MediaStringViewTest, ShouldHasDifferentTransform) {
  SetAmbientShownAndWaitForWidgets();

  // Sets metadata for current session.
  media_session::MediaMetadata metadata;
  metadata.title = u"title";
  metadata.artist = u"artist";

  SimulateMediaPlaybackStateChanged(
      media_session::mojom::MediaPlaybackState::kPlaying);
  SimulateMediaMetadataChanged(metadata);
  EXPECT_TRUE(GetMediaStringView()->GetVisible());

  // It is theoretically that the transforms could be the same in two
  // consecutive updates, therefore we test with two updates.
  gfx::Transform transform1 =
      GetMediaStringView()->layer()->GetTargetTransform();
  FastForwardByPhotoRefreshInterval();
  FastForwardByPhotoRefreshInterval();
  gfx::Transform transform2 =
      GetMediaStringView()->layer()->GetTargetTransform();
  EXPECT_NE(transform1, transform2);
}

}  // namespace ash