#include "media/gpu/android/surface_chooser_helper.h"
#include <stdint.h>
#include <memory>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/gpu/android/mock_android_video_surface_chooser.h"
#include "media/gpu/android/mock_promotion_hint_aggregator.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::AtLeast;
namespace media {
class SurfaceChooserHelperTest : public testing::Test {
public:
~SurfaceChooserHelperTest() override {}
void SetUp() override {
ReplaceHelper(false, false);
}
void TearDown() override {}
void ReplaceHelper(bool is_overlay_required,
bool promote_secure_only,
bool always_use_texture_owner = false) {
tick_clock_.Advance(base::Seconds(10000));
std::unique_ptr<MockAndroidVideoSurfaceChooser> chooser =
std::make_unique<MockAndroidVideoSurfaceChooser>();
chooser_ = chooser.get();
std::unique_ptr<MockPromotionHintAggregator> aggregator =
std::make_unique<MockPromotionHintAggregator>();
aggregator_ = aggregator.get();
helper_ = std::make_unique<SurfaceChooserHelper>(
std::move(chooser), is_overlay_required, promote_secure_only,
always_use_texture_owner, std::move(aggregator), &tick_clock_);
}
void UpdateChooserState() {
EXPECT_CALL(*chooser_, MockUpdateState());
helper_->UpdateChooserState(std::optional<AndroidOverlayFactoryCB>());
}
base::SimpleTestTickClock tick_clock_;
raw_ptr<MockPromotionHintAggregator> aggregator_ = nullptr;
raw_ptr<MockAndroidVideoSurfaceChooser> chooser_ = nullptr;
std::unique_ptr<SurfaceChooserHelper> helper_;
};
TEST_F(SurfaceChooserHelperTest, SetIsFullscreen) {
helper_->SetIsFullscreen(true);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_fullscreen);
ASSERT_TRUE(chooser_->current_state_.is_expecting_relayout);
helper_->SetIsFullscreen(false);
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.is_fullscreen);
}
TEST_F(SurfaceChooserHelperTest, SetVideoRotation) {
helper_->SetVideoRotation(VIDEO_ROTATION_90);
UpdateChooserState();
ASSERT_EQ(chooser_->current_state_.video_rotation, VIDEO_ROTATION_90);
}
TEST_F(SurfaceChooserHelperTest, SetIsPersistentVideo) {
helper_->SetIsPersistentVideo(true);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_persistent_video);
helper_->SetIsPersistentVideo(false);
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.is_persistent_video);
}
TEST_F(SurfaceChooserHelperTest, SetIsOverlayRequired) {
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.is_required);
ReplaceHelper(true, false);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_required);
}
TEST_F(SurfaceChooserHelperTest, SetInsecureSurface) {
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kInsecure);
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.is_secure);
ASSERT_FALSE(chooser_->current_state_.is_required);
}
TEST_F(SurfaceChooserHelperTest, SetRequestedSecureSurface) {
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kRequested);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_secure);
ASSERT_FALSE(chooser_->current_state_.is_required);
}
TEST_F(SurfaceChooserHelperTest, SetRequiredSecureSurface) {
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kRequired);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_secure);
ASSERT_TRUE(chooser_->current_state_.is_required);
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kInsecure);
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.is_required);
}
TEST_F(SurfaceChooserHelperTest, StillRequiredAfterClearingSecure) {
ReplaceHelper(true, false);
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kRequired);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_required);
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kInsecure);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_required);
}
TEST_F(SurfaceChooserHelperTest, SetPromoteSecureOnly) {
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.promote_secure_only);
ReplaceHelper(false, true);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.promote_secure_only);
}
TEST_F(SurfaceChooserHelperTest, SetAlwaysUseTextureOwner) {
UpdateChooserState();
ASSERT_FALSE(chooser_->current_state_.always_use_texture_owner);
ReplaceHelper(false, true, true);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.always_use_texture_owner);
}
TEST_F(SurfaceChooserHelperTest, PromotionHintsForwardsHint) {
PromotionHintAggregator::Hint hint(gfx::Rect(1, 2, 3, 4), false);
EXPECT_CALL(*aggregator_, NotifyPromotionHint(hint));
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
}
TEST_F(SurfaceChooserHelperTest, PromotionHintsRelayPosition) {
gfx::Rect rect(0, 1, 2, 3);
helper_->NotifyPromotionHintAndUpdateChooser(
PromotionHintAggregator::Hint(rect, true), false);
ASSERT_EQ(chooser_->current_state_.initial_position, rect);
}
TEST_F(SurfaceChooserHelperTest, PromotionHintsRelayPromotable) {
EXPECT_CALL(*chooser_, MockUpdateState()).Times(AtLeast(1));
PromotionHintAggregator::Hint hint(gfx::Rect(), false);
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
ASSERT_FALSE(chooser_->current_state_.is_compositor_promotable);
aggregator_->SetIsSafeToPromote(true);
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
ASSERT_TRUE(chooser_->current_state_.is_compositor_promotable);
}
TEST_F(SurfaceChooserHelperTest, PromotionHintsClearRelayoutFlag) {
helper_->SetIsFullscreen(true);
UpdateChooserState();
ASSERT_TRUE(chooser_->current_state_.is_expecting_relayout);
EXPECT_CALL(*chooser_, MockUpdateState()).Times(AtLeast(1));
for (int i = 0; i < 15; i++) {
PromotionHintAggregator::Hint hint(gfx::Rect(), false);
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
}
ASSERT_FALSE(chooser_->current_state_.is_expecting_relayout);
}
TEST_F(SurfaceChooserHelperTest, PromotionHintsUpdateChooserStatePeriodically) {
PromotionHintAggregator::Hint hint(gfx::Rect(), false);
aggregator_->SetIsSafeToPromote(true);
EXPECT_CALL(*chooser_, MockUpdateState()).Times(1);
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
EXPECT_CALL(*chooser_, MockUpdateState()).Times(0);
helper_->NotifyPromotionHintAndUpdateChooser(hint, true);
EXPECT_CALL(*chooser_, MockUpdateState()).Times(0);
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
tick_clock_.Advance(base::Seconds(10));
EXPECT_CALL(*chooser_, MockUpdateState()).Times(0);
helper_->NotifyPromotionHintAndUpdateChooser(hint, true);
EXPECT_CALL(*chooser_, MockUpdateState()).Times(1);
helper_->NotifyPromotionHintAndUpdateChooser(hint, false);
}
TEST_F(SurfaceChooserHelperTest, FrameInformationIsCorrectForL1) {
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kRequired);
ASSERT_EQ(SurfaceChooserHelper::FrameInformation::OVERLAY_L1,
helper_->ComputeFrameInformation(true));
}
TEST_F(SurfaceChooserHelperTest, FrameInformationIsCorrectForL3) {
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kRequested);
ASSERT_EQ(SurfaceChooserHelper::FrameInformation::OVERLAY_L3,
helper_->ComputeFrameInformation(true));
ASSERT_EQ(SurfaceChooserHelper::FrameInformation::NON_OVERLAY_L3,
helper_->ComputeFrameInformation(false));
}
TEST_F(SurfaceChooserHelperTest, FrameInformationIsCorrectForInsecure) {
helper_->SetSecureSurfaceMode(
SurfaceChooserHelper::SecureSurfaceMode::kInsecure);
ASSERT_EQ(SurfaceChooserHelper::FrameInformation::NON_OVERLAY_INSECURE,
helper_->ComputeFrameInformation(false));
helper_->SetIsFullscreen(true);
ASSERT_EQ(SurfaceChooserHelper::FrameInformation::
OVERLAY_INSECURE_PLAYER_ELEMENT_FULLSCREEN,
helper_->ComputeFrameInformation(true));
helper_->SetIsFullscreen(false);
ASSERT_EQ(SurfaceChooserHelper::FrameInformation::
OVERLAY_INSECURE_NON_PLAYER_ELEMENT_FULLSCREEN,
helper_->ComputeFrameInformation(true));
}
}