blob: aa2bc02dbbb54a9046f921f8f7da11b47b8d049b [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/shelf/contextual_tooltip.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/contextual_nudge_status_tracker.h"
#include "ash/shelf/contextual_tooltip.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/strings/string_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/util/values/values_util.h"
#include "base/values.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "ui/aura/window.h"
#include "ui/wm/core/window_util.h"
namespace ash {
namespace contextual_tooltip {
class ContextualTooltipTest : public AshTestBase,
public testing::WithParamInterface<bool> {
public:
ContextualTooltipTest() {
if (GetParam()) {
scoped_feature_list_.InitWithFeatures(
{ash::features::kContextualNudges,
ash::features::kHideShelfControlsInTabletMode},
{});
} else {
scoped_feature_list_.InitAndDisableFeature(
ash::features::kContextualNudges);
}
}
~ContextualTooltipTest() override = default;
base::SimpleTestClock* clock() { return &test_clock_; }
// AshTestBase:
void SetUp() override {
AshTestBase::SetUp();
contextual_tooltip::OverrideClockForTesting(&test_clock_);
test_clock_.Advance(base::TimeDelta::FromSeconds(360));
}
void TearDown() override {
contextual_tooltip::ClearStatusTrackerTableForTesting();
contextual_tooltip::ClearClockOverrideForTesting();
AshTestBase::TearDown();
}
PrefService* GetPrefService() {
return Shell::Get()->session_controller()->GetLastActiveUserPrefService();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
base::SimpleTestClock test_clock_;
};
using ContextualTooltipDisabledTest = ContextualTooltipTest;
INSTANTIATE_TEST_SUITE_P(All,
ContextualTooltipDisabledTest,
testing::Values(false));
INSTANTIATE_TEST_SUITE_P(All, ContextualTooltipTest, testing::Values(true));
// Checks that nudges are not shown when the feature flag is disabled.
TEST_P(ContextualTooltipDisabledTest, FeatureFlagDisabled) {
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
}
TEST_P(ContextualTooltipTest, ShouldShowPersistentDragHandleNudge) {
base::TimeDelta recheck_delay;
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_TRUE(recheck_delay.is_zero());
EXPECT_TRUE(contextual_tooltip::GetNudgeTimeout(GetPrefService(),
TooltipType::kInAppToHome)
.is_zero());
}
// Checks that drag handle nudge has a timeout if it is not the first time it is
// being shown.
TEST_P(ContextualTooltipTest, NonPersistentDragHandleNudgeTimeout) {
for (int shown_count = 1;
shown_count < contextual_tooltip::kNotificationLimit; shown_count++) {
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kInAppToHome);
clock()->Advance(contextual_tooltip::kMinInterval);
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
EXPECT_EQ(contextual_tooltip::GetNudgeTimeout(GetPrefService(),
TooltipType::kInAppToHome),
contextual_tooltip::kNudgeShowDuration);
}
}
// Checks that drag handle nudge should be shown after kMinInterval has passed
// since the last time it was shown but not before the time interval has passed.
TEST_P(ContextualTooltipTest, ShouldShowTimedDragHandleNudge) {
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kInAppToHome);
base::TimeDelta recheck_delay;
for (int shown_count = 1;
shown_count < contextual_tooltip::kNotificationLimit; shown_count++) {
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_EQ(contextual_tooltip::kMinInterval, recheck_delay);
clock()->Advance(contextual_tooltip::kMinInterval / 2);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_EQ(
contextual_tooltip::kMinInterval - contextual_tooltip::kMinInterval / 2,
recheck_delay);
clock()->Advance(contextual_tooltip::kMinInterval / 2);
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kInAppToHome);
}
clock()->Advance(contextual_tooltip::kMinInterval);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_TRUE(recheck_delay.is_zero());
EXPECT_EQ(contextual_tooltip::GetNudgeTimeout(GetPrefService(),
TooltipType::kInAppToHome),
contextual_tooltip::kNudgeShowDuration);
}
// Tests that if the user has successfully performed the gesture for at least
// |kSuccessLimit|, the corresponding nudge should not be shown.
TEST_P(ContextualTooltipTest, ShouldNotShowNudgeAfterSuccessLimit) {
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
for (int success_count = 0;
success_count < contextual_tooltip::kSuccessLimitInAppToHome;
success_count++) {
contextual_tooltip::HandleGesturePerformed(GetPrefService(),
TooltipType::kInAppToHome);
}
base::TimeDelta recheck_delay;
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_TRUE(recheck_delay.is_zero());
}
// Should not show back gesture nudge if drag handle nudge is expected to be
// shown.
TEST_P(ContextualTooltipTest,
DoNotShowBackGestureNudgeIfDragHandleNudgeIsExpected) {
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
// The drag handle nudge is expected to show, so back gesture nudge should not
// be shown at the same time.
base::TimeDelta recheck_delay;
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, &recheck_delay));
EXPECT_EQ(contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge,
recheck_delay);
// After the nudge is shown, back gesture should remain hidden until
// sufficient amount of time passes.
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kInAppToHome);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, &recheck_delay));
EXPECT_EQ(contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge,
recheck_delay);
clock()->Advance(
contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge / 2);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, &recheck_delay));
EXPECT_EQ(
contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge -
contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge / 2,
recheck_delay);
clock()->Advance(recheck_delay);
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, nullptr));
// After the drag handle becomes eligible to show again, the back gesture
// should be disabled.
clock()->Advance(contextual_tooltip::kMinInterval);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, &recheck_delay));
EXPECT_EQ(contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge,
recheck_delay);
}
// Tests that back gesture is allowed if the shelf is hidden, even if drag
// handle would normally be available.
TEST_P(ContextualTooltipTest, AllowBackGestureForHiddenShelf) {
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
// The drag handle nudge is expected to show, so back gesture nudge should not
// be shown at the same time.
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, nullptr));
// If drag handle nudge is disabled because the shelf is hidden, the back
// gesture nudge should be allowed.
contextual_tooltip::SetDragHandleNudgeDisabledForHiddenShelf(true);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, nullptr));
// Disallow back gesture nudge if the shelf becomes visible.
contextual_tooltip::SetDragHandleNudgeDisabledForHiddenShelf(false);
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kBackGesture, nullptr));
}
// Tests that the drag handle nudge should not be shown while back gesture is
// showing, or soon after it's been shown.
TEST_P(ContextualTooltipTest,
DoNotShowDragHandleNudgeIfBackGestureNudgeIsShown) {
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
// Drag handle nudge not allowed if back gesture is showing.
contextual_tooltip::SetDragHandleNudgeDisabledForHiddenShelf(true);
contextual_tooltip::SetBackGestureNudgeShowing(true);
contextual_tooltip::SetDragHandleNudgeDisabledForHiddenShelf(false);
base::TimeDelta recheck_delay;
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_EQ(contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge,
recheck_delay);
// Allow drag handle only if sufficient amount of time passes since showing
// the back gesture nudge.
contextual_tooltip::SetBackGestureNudgeShowing(false);
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kBackGesture);
recheck_delay = base::TimeDelta();
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
EXPECT_EQ(contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge,
recheck_delay);
clock()->Advance(
contextual_tooltip::kMinIntervalBetweenBackAndDragHandleNudge / 2);
EXPECT_FALSE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, &recheck_delay));
clock()->Advance(recheck_delay);
EXPECT_TRUE(contextual_tooltip::ShouldShowNudge(
GetPrefService(), TooltipType::kInAppToHome, nullptr));
}
// Tests that status tracker is activated on nudge shown and deactivated after
// a gesture is performed or the nudge state is exited.
TEST_P(ContextualTooltipTest, DragHandleNudgeMetrics) {
// Showing the nudge activates the status tracker.
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kInAppToHome);
EXPECT_TRUE(CanRecordNudgeHiddenMetricForTesting(TooltipType::kInAppToHome));
// Performing the gesture should deactivate the status tracker.
contextual_tooltip::HandleGesturePerformed(GetPrefService(),
TooltipType::kInAppToHome);
EXPECT_FALSE(CanRecordNudgeHiddenMetricForTesting(TooltipType::kInAppToHome));
// Showing the nudge should reactivate the tracker.
contextual_tooltip::HandleNudgeShown(GetPrefService(),
TooltipType::kInAppToHome);
EXPECT_TRUE(
CanRecordGesturePerformedMetricForTesting(TooltipType::kInAppToHome));
// Tracker should remain active when exiting the nudge state via kOther
// but should reset visibility. Tracker should be deactivated after gesture is
// performed.
contextual_tooltip::MaybeLogNudgeDismissedMetrics(TooltipType::kInAppToHome,
DismissNudgeReason::kOther);
EXPECT_TRUE(
CanRecordGesturePerformedMetricForTesting(TooltipType::kInAppToHome));
EXPECT_FALSE(CanRecordNudgeHiddenMetricForTesting(TooltipType::kInAppToHome));
contextual_tooltip::HandleGesturePerformed(GetPrefService(),
TooltipType::kInAppToHome);
EXPECT_FALSE(
CanRecordGesturePerformedMetricForTesting(TooltipType::kInAppToHome));
}
} // namespace contextual_tooltip
} // namespace ash